IFS
曖昧性解消
IFS
として、入力フィールドセパレータを意味しlist of characters that could be used as separators
ます。
デフォルトでは、これはに設定されています。これは 、スペース、集計、および/または改行
\t\n
の任意の数(ゼロより大きい)を1にすることができることを意味します。 separator
したがって、文字列:
" blah foo=bar
baz "
先頭と末尾の区切り文字は無視され、この文字列には、、、の3つの部分のみが含まblah
れfoo=bar
ますbaz
。
IFS
文字列で使用されていない有効なフィールドセパレータがわかっている場合は、を使用して文字列を分割できます。
OIFS="$IFS"
IFS='§'
c=$'AA=A\nB=BB\n=======\nC==CC\nDD=D\n=======\nEEE\nFF'
c_split=(${c//=======/§})
IFS="$OIFS"
printf -- "------ new part ------\n%s\n" "${c_split[@]}"
------ new part ------
AA=A
B=BB
------ new part ------
C==CC
DD=D
------ new part ------
EEE
FF
ただし、これは文字列にが含まれていない場合にのみ機能します§
。
のように別のキャラクターを使用することもできますIFS=$'\026';c_split=(${c//=======/$'\026'})
が、とにかくこれにはさらにバグが含まれる可能性があります。
文字列に含まれていないものを見つけるために文字コード表を参照できます。
myIfs=""
for i in {1..255};do
printf -v char "$(printf "\\\%03o" $i)"
[ "$c" == "${c#*$char}" ] && myIfs="$char" && break
done
if ! [ "$myIFS" ] ;then
echo no split char found, could not do the job, sorry.
exit 1
fi
しかし、私はこの解決策が少しやり過ぎだと思います。
スペースでの分割(またはIFSを変更せずに)
bashの下では、次のbashismを使用できます。
b="aaaaa/bbbbb/ddd/ffffff"
b_split=(${b//// })
実際、この構文は、配列に割り当てる前に、すべての出現箇所をスペースで置き換える${varname//
変換(で区切られる)を開始します。/
/
b_split
もちろん、これはまだIFS
スペースで配列を使用して分割します。
これは最善の方法ではありませんが、特定のケースで機能する可能性があります。
分割する前に不要なスペースを削除することもできます。
b='12 34 / 1 3 5 7 / ab'
b1=${b// }
b_split=(${b1//// })
printf "<%s>, " "${b_split[@]}" ;echo
<12>, <34>, <1>, <3>, <5>, <7>, <ab>,
またはそれらを交換します。
b1=${b// /§}
b_split=(${b1//// })
printf "<%s>, " "${b_split[@]//§/ }" ;echo
<12 34 >, < 1 3 5 7 >, < ab>,
上の分割線strings
:
したがって、自分の意味で使用する必要はありませんが、 bashには優れた機能があります。IFS
#!/bin/bash
c=$'AA=A\nB=BB\n=======\nC==CC\nDD=D\n=======\nEEE\nFF'
echo "more complex string"
echo "$c";
echo ;
echo "split";
mySep='======='
while [ "$c" != "${c#*$mySep}" ];do
echo "------ new part ------"
echo "${c%%$mySep*}"
c="${c#*$mySep}"
done
echo "------ last part ------"
echo "$c"
見てみましょう:
more complex string
AA=A
B=BB
=======
C==CC
DD=D
=======
EEE
FF
split
------ new part ------
AA=A
B=BB
------ new part ------
C==CC
DD=D
------ last part ------
EEE
FF
注:先頭と末尾の改行は削除されません。これが必要な場合は、次のことができます。
mySep=$'\n=======\n'
単にの代わりに=======
。
または、これを明示的に排除するために分割ループを書き直すことができます。
mySep=$'======='
while [ "$c" != "${c#*$mySep}" ];do
echo "------ new part ------"
part="${c%%$mySep*}"
part="${part##$'\n'}"
echo "${part%%$'\n'}"
c="${c#*$mySep}"
done
echo "------ last part ------"
c=${c##$'\n'}
echo "${c%%$'\n'}"
いずれにせよ、これはSOの質問が求めたものと一致します(:と彼のサンプル:)
------ new part ------
AA=A
B=BB
------ new part ------
C==CC
DD=D
------ last part ------
EEE
FF
最終的に作成するarray
#!/bin/bash
c=$'AA=A\nB=BB\n=======\nC==CC\nDD=D\n=======\nEEE\nFF'
echo "more complex string"
echo "$c";
echo ;
echo "split";
mySep=$'======='
export -a c_split
while [ "$c" != "${c#*$mySep}" ];do
part="${c%%$mySep*}"
part="${part##$'\n'}"
c_split+=("${part%%$'\n'}")
c="${c#*$mySep}"
done
c=${c##$'\n'}
c_split+=("${c%%$'\n'}")
for i in "${c_split[@]}"
do
echo "------ new part ------"
echo "$i"
done
これを細かく行います:
more complex string
AA=A
B=BB
=======
C==CC
DD=D
=======
EEE
FF
split
------ new part ------
AA=A
B=BB
------ new part ------
C==CC
DD=D
------ new part ------
EEE
FF
いくつかの説明:
export -a var
配列として定義var
し、それらを子で共有します
${variablename%string*}
、${variablename%%string*}
結果は変数名の左側になりますが、文字列は含まれません。文字列の最後の出現を%
意味し、すべての出現に対して。完全な変数名が返されますが、文字列が見つかりません。%%
${variablename#*string}
、逆の方法で同じことを行います。変数名の最後の部分を文字列から返しますが、文字列は返しません。1つは最初の発生#
を意味し、2人はすべての発生を意味します。##
代わりに、文字*
はジョーカーであり、任意の数の任意の文字を意味します。
このコマンドは変数cecho "${c%%$'\n'}"
をエコーしますが、文字列の最後に改行はありません。
したがって、変数にが含まれている場合Hello WorldZorGluBHello youZorGluBI'm happy
、
variable="Hello WorldZorGluBHello youZorGluBI'm happy"
$ echo ${variable#*ZorGluB}
Hello youZorGlubI'm happy
$ echo ${variable##*ZorGluB}
I'm happy
$ echo ${variable%ZorGluB*}
Hello WorldZorGluBHello you
$ echo ${variable%%ZorGluB*}
Hello World
$ echo ${variable%%ZorGluB}
Hello WorldZorGluBHello youZorGluBI'm happy
$ echo ${variable%happy}
Hello WorldZorGluBHello youZorGluBI'm
$ echo ${variable##* }
happy
これはすべて、マンページで説明されています。
$ man -Len -Pless\ +/##word bash
$ man -Len -Pless\ +/%%word bash
$ man -Len -Pless\ +/^\\\ *export\\\ .*word bash
ステップバイステップ、分割ループ:
セパレータ:
mySep=$'======='
配列c_split
として宣言する(そして子と共有することができます)
export -a c_split
変数cには、少なくとも1つのオカレンスが含まれていますがmySep
while [ "$c" != "${c#*$mySep}" ];do
cを文字列の最初から最後まで切り捨てmySep
、に割り当てpart
ます。
part="${c%%$mySep*}"
主要な改行を削除する
part="${part##$'\n'}"
末尾の改行を削除し、結果を新しい配列要素としてに追加しc_split
ます。
c_split+=("${part%%$'\n'}")
そのままにしておくと、残りの弦を取り除いてcを解放しますmySep
c="${c#*$mySep}"
終わり ;-)
done
主要な改行を削除する
c=${c##$'\n'}
末尾の改行を削除し、結果を新しい配列要素としてに追加しc_split
ます。
c_split+=("${c%%$'\n'}")
関数に:
ssplit() {
local string="$1" array=${2:-ssplited_array} delim="${3:- }" pos=0
while [ "$string" != "${string#*$delim}" ];do
printf -v $array[pos++] "%s" "${string%%$delim*}"
string="${string#*$delim}"
done
printf -v $array[pos] "%s" "$string"
}
使用法:
ssplit "<quoted string>" [array name] [delimiter string]
ここで、配列名は$splitted_array
デフォルトであり、区切り文字は1つの単一スペースです。
あなたが使用することができます:
c=$'AA=A\nB=BB\n=======\nC==CC\nDD=D\n=======\nEEE\nFF'
ssplit "$c" c_split $'\n=======\n'
printf -- "--- part ----\n%s\n" "${c_split[@]}"
--- part ----
AA=A
B=BB
--- part ----
C==CC
DD=D
--- part ----
EEE
FF