なぜ次のbashコードが動作しないのですか?文字列をbashの複数文字区切り文字に分割する方法は?
for i in $(echo "emmbbmmaaddsb" | split -t "mm" )
do
echo "$i"
done
予想される出力:
e
bb
aaddsb
なぜ次のbashコードが動作しないのですか?文字列をbashの複数文字区切り文字に分割する方法は?
for i in $(echo "emmbbmmaaddsb" | split -t "mm" )
do
echo "$i"
done
予想される出力:
e
bb
aaddsb
あなたは改行を期待しているので、あなたは単に改行を使用して文字列内のmm
のすべてのインスタンスを置き換えることができます。純粋なネイティブbashで:
in='emmbbmmaaddsb'
sep='mm'
printf '%s\n' "${in//$sep/$'\n'}"
あなたが長く、入力ストリーム上にそのような交換をしたいと思った場合はbashの組み込みの文字列操作がにうまくスケールしないよう、あなたは、awk
を使用したほうが良いかもしれません数キロバイト以上のコンテンツで与えられる(awk
にbackending)gsub_literal
シェル関数を適用することが可能である:
# Taken from http://mywiki.wooledge.org/BashFAQ/021
# usage: gsub_literal STR REP
# replaces all instances of STR with REP. reads from stdin and writes to stdout.
gsub_literal() {
# STR cannot be empty
[[ $1 ]] || return
# string manip needed to escape '\'s, so awk doesn't expand '\n' and such
awk -v str="${1//\\/\\\\}" -v rep="${2//\\/\\\\}" '
# get the length of the search string
BEGIN {
len = length(str);
}
{
# empty the output string
out = "";
# continue looping while the search string is in the line
while (i = index($0, str)) {
# append everything up to the search string, and the replacement string
out = out substr($0, 1, i-1) rep;
# remove everything up to and including the first instance of the
# search string from the line
$0 = substr($0, i + len);
}
# append whatever is left
out = out $0;
print out;
}
'
}
...ように、この文脈において、使用される:bashので
gsub_literal "mm" $'\n' <your-input-file.txt >your-output-file.txt
:
s="emmbbmmaaddsb"
for i in "${s//mm/$'\n'}"; do echo "$i"; done
出力:
e bb aaddsb
これは何も分割しません... 'mm'を改行で置き換えるだけです。 'echo $ {s // m/$ '\ n'}' 'を実行して' for'ループを完全に削除することもできます。 –
@gniourf_gniourf:私は質問者がすべての行で何かをしたいと思っていました。 – Cyrus
しかし、あなたが書いた方法である 'for'ループは、各行でループしません。単一の文字列 '$ 'e \ nbb \ naaddsb'で一回のみループします。 –
文字のサブタイトルに推奨されるツールは、正規表現の場合はsed
のコマンドs/regexp/replacement/
、グローバルの場合はs/regexp/replacement/g
です。ループや変数は必要ありません。
パイプあなたのecho
出力と改行文字\n
witht文字にmm
を代用してみてください:出力がある
echo "emmbbmmaaddsb" | sed 's/mm/\n/g'
:
e
bb
aaddsb
「推奨」ですか? bashの文字列操作に関するベストプラクティスのガイダンスについては、[BashFAQ#100](http://mywiki.wooledge.org/BashFAQ/100)を参照してください。パラメータの拡張は一般的に、短い入力に対してはベストプラクティスのアプローチと見なされます(ただし、 'echo | sed 'アプローチは簡潔ではあるが、それがどのように実装されているかという点でオーバーヘッドが大きい)典型的には2つのフォーク、mkfifo、リンクとロードが必要な外部ツールの 'execv'など)が必要です。 –
...タイトなループで入力を1行ずつ処理している場合(または、数百または数千のファイル名を含むグロブ結果を反復処理する場合)、 'echo |各行に対して「sed」は絶対に反パターンになります。 (入力ストリーム全体を処理する 'sed' *を1回だけ呼び出す*とは対照的に、しばしば適切です)。 –
より一般的な例として、マルチを交換することなく、単一の文字区切り文字を持つ-character delimiterは次のとおりです。
パラメータ拡張を使用:リファレンス
#!/bin/bash
# main string
str="LearnABCtoABCSplitABCaABCString"
# delimiter string
delimiter="ABC"
#length of main string
strLen=${#str}
#length of delimiter string
dLen=${#delimiter}
#iterator for length of string
i=0
#length tracker for ongoing substring
wordLen=0
#starting position for ongoing substring
strP=0
array=()
while [ $i -lt $strLen ]; do
if [ $delimiter == ${str:$i:$dLen} ]; then
array+=(${str:strP:$wordLen})
strP=$((i + dLen))
wordLen=0
i=$((i + dLen))
fi
i=$((i + 1))
wordLen=$((wordLen + 1))
done
array+=(${str:strP:$wordLen})
declare -p array
方法のより多くの粗種類
#!/bin/bash
str="LearnABCtoABCSplitABCaABCString"
delimiter=ABC
s=$str$delimiter
array=();
while [[ $s ]]; do
array+=("${s%%"$delimiter"*}");
s=${s#*"$delimiter"};
done;
declare -p array
(@gniourf_gniourfのコメントから) - ハァッ... Bash Split String
これは壊れています(文字列にグロブ文字やスペースなどが含まれていると失敗します)。さらに、現代のBashイディオムを使用していないので、コードが本当に奇妙に見えます。 'str =" LearnABCtoABCSplitABCaABCString "delimiter = ABC s = $ str $ delimiter array =();単純なループが必要です。 while [[$ s]];配列+ =( "$ {s %%" $デリミタ "*}"); s = $ {s#* "$区切り文字"};完了しました。宣言-p配列 '。それで全部です。 –
@gniourf_gniourfありがとうございました。私はBash Scriptingを始めました。あなたの提案は、慣用的なアプローチで考えるのに本当に役立ちます。 –
からBash Tutorial?それは「分割」がまったく何をするのではない。 **実際の機能とは完全に無関係です**。 –
bashの任意の複数文字の区切り文字に任意の文字列を分割する方法を知りたいですか?あなたが本当に知りたいことがあれば、その質問を編集するのはなぜですか? –
@CharlesDuffyあなたの意見で分裂は何をするのですか? – v217