JavaScriptでsplit()
を使用して文字列を配列に分割するのは非常に簡単です。
シェルスクリプトはどうですか?
これをやりたいとしましょう:
$ script.sh var1_var2_var3
ユーザーがそのような文字列var1_var2_var3
をscript.shに追加します。スクリプト内では、文字列を次のような配列に変換します
array=( var1 var2 var3 )
for name in ${array[@]}; do
# some code
done
Bourne/POSIXのようなシェルにはsplit + glob演算子があり、パラメーター展開(_$var
_、_$-
_...)、コマンド置換($(...)
)を終了するたびに呼び出されます、またはリストのコンテキストで引用符で囲まれていない算術展開($((...))
)。
実際、_for name in ${array[@]}
_の代わりに_for name in "${array[@]}"
_を実行したときに誤って呼び出しました。 (実際には、 誤ってそのような演算子を呼び出すと、多くのバグやセキュリティの脆弱性の原因となることに注意してください )。
その演算子は、_$IFS
_特殊パラメーター(どの文字に分割するかを伝えるために(ただし、スペース、タブ、および改行がそこで特別な扱いを受けることに注意してください))および_-f
_オプションを使用して無効にします(_set -f
_)または(_set +f
_)glob
パーツを有効にします。
また、_$IFS
_のS
はもともと(_$IFS
_が由来するBourne Shell内) S区切り文字、POSIXシェルでは、_$IFS
_の文字は区切り文字またはターミネータ(以下を参照)例)。
したがって、__
_で分割するには:
_string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
array=($string) # invoke the split+glob operator
for i in "${array[@]}"; do # loop over the array elements.
_
separatorとdelimiterの違いを確認するには、次を試してください:
_string='var1_var2_'
_
それはそれを_var1
_と_var2
_のみに分割します(余分な空の要素はありません)。
したがって、それをJavaScriptのsplit()
に類似させるには、追加の手順が必要になります。
_string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
temp=${string}_ # add an extra delimiter
array=($temp) # invoke the split+glob operator
_
(空の_$string
_を1(not)要素に分割することに注意してください、JavaScriptのsplit()
など)。
特別な扱いのタブ、スペース、改行の受け取りを確認するには、以下を比較してください。
_IFS=' '; string=' var1 var2 '
_
(_var1
_と_var2
_を取得する場所)
_IFS='_'; string='_var1__var2__'
_
取得場所:_''
_、_var1
_、_''
_、_var2
_、_''
_。
zsh
またはsh
エミュレーションでない限り、ksh
シェルはそのようなsplit + glob演算子を暗黙的に呼び出さないことに注意してください。そこで、明示的に呼び出す必要があります。 _$=string
_はスプリットパーツ、_$~string
_はグロブパーツ(_$=~string
_は両方)のほか、セパレーターを指定できるスプリット演算子もあります。
_array=(${(s:_:)string})
_
または空の要素を保持するには:
_array=("${(@s:_:)string}")
_
そこにs
は分割用であり、区切り用ではない(また、既知の_$IFS
_と一緒に) POSIX非準拠zsh
)。 JavaScriptのsplit()
とは異なり、空の文字列は0(1ではない)要素に分割されます。
_$IFS
_分割との顕著な違いは、${(s:abc:)string}
がabc
文字列で分割されるのに対し、_IFS=abc
_はa
で分割されることです。 b
またはc
。
zsh
および_ksh93
_を使用すると、スペース、タブ、または改行が受け取る特別な扱いを、_$IFS
_で2倍にすることによって削除できます。
歴史的なメモとして、ボーンシェル(祖先または最新のPOSIXシェル)は常に空の要素を取り除きました。また、デフォルト以外の値が_$IFS
_である$ @の分割と展開に関連する多くのバグがありました。たとえば、_IFS=_; set -f; set -- $@
_は_IFS=_; set -f; set -- $1 $2 $3...
_と同等ではありません。
正規表現で分割できるJavaScriptのsplit()
に近いものを作成するには、外部ユーティリティに依存する必要があります。
POSIXツールチェストでは、awk
にはsplit
演算子があり、拡張正規表現で分割できます(これらは多かれ少なかれのサブセットです) JavaScriptでサポートされているPerlのような正規表現)。
_split() {
awk -v q="'" '
function quote(s) {
gsub(q, q "\\" q q, s)
return q s q
}
BEGIN {
n = split(ARGV[1], a, ARGV[2])
for (i = 1; i <= n; i++) printf " %s", quote(a[i])
exit
}' "$@"
}
string=a__b_+c
eval "array=($(split "$string" '[_+]+'))"
_
zsh
シェルには、Perl互換の正規表現(_zsh/pcre
_モジュール内)のサポートが組み込まれていますが、これを使用して文字列を分割することは可能ですが、比較的面倒です。
はい、IFS
を使用して_
に設定します。次に、read -a
を使用して配列に格納します(-r
はバックスラッシュ展開をオフにします)。これはbashに固有のものであることに注意してください。 kshとzshには同様の機能があり、構文は少し異なります。プレーンなshには配列変数がありません。
$ r="var1_var2_var3"
$ IFS='_' read -r -a array <<< "$r"
$ for name in "${array[@]}"; do echo "+ $name"; done
+ var1
+ var2
+ var3
man bash
から:
読み取り
-a名前
単語は、配列変数anameの0から始まる連続したインデックスに割り当てられます。anameは、新しい値が割り当てられる前に設定解除されます。他の名前引数は無視されます。
[〜#〜] ifs [〜#〜]
拡張後のワード分割に使用され、組み込みコマンドreadで行をワードに分割するために使用される内部フィールドセパレータ。デフォルト値は「」です。
read
は最初の改行で停止することに注意してください。それを避けるために-d ''
をread
に渡しますが、その場合、<<<
演算子が原因で最後に余分な改行があります。手動で削除できます:
IFS='_' read -r -d '' -a array <<< "$r"
array[$((${#array[@]}-1))]=${array[$((${#array[@]}-1))]%?}