シェルにJavaScriptの「split()」のようなものがありますか?

シェルにJavaScriptの「split()」のようなものがありますか?

split()文字列を配列に分割するのはJavaScriptで非常に簡単です。

シェルスクリプトはどうですか?

私がこれをしたいとしましょう:

$ script.sh var1_var2_var3

ユーザーがscript.shにこれらの文字列を提供すると、var1_var2_var3スクリプト内で文字列を配列に変換します。

array=( var1 var2 var3 )
for name in ${array[@]}; do
    # some code
done

答え1

$varBourne / POSIXに似たシェルには、リストコンテキストで引用符で囲まれていない引数拡張(、$-...)、コマンド置換()、または算術拡張()があるたびに$(...)呼び出される分割+glob演算子があります。$((...))

for name in ${array[@]}実際に代わりに呼び出したときに間違って呼び出しましたfor name in "${array[@]}"。 (事実に注意すべき点はこの演算子を誤って呼び出すと、多くのバグやセキュリティの脆弱性が発生します。)。

$IFSこの演算子は、分割する文字を示す特別なパラメータ(ただし、スペース、タブ、および改行文字はここで特別に処理されます)と、そのセクションを無効にする()または有効にする)オプションで構成されて-fset -fます。set +fglob

また、Sinは$IFS元々(Bourneシェルで$IFSS区切り文字として使用されていましたが、POSIXシェルではinの文字を次の$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.

違いを見るには仕切りそして区切り記号、試してみてください:

string='var1_var2_'

var1これにより and にのみ分割されます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

$stringNullを次のように分割します。1(いいえ0)要素(例:JavaScriptのsplit())。

タブ、スペース、改行の特別な処理を表示するには、次のように比較します。

IFS=' '; string=' var1  var2  '

(合計を得るvar1ところvar2

IFS='_'; string='_var1__var2__'

'', var1, '', var2, ''.

zshシェルは、inまたはエミュレーションを除いて、このような分割+glob演算子を暗黙的に呼び出しません。そこから明示的に呼び出す必要があります。分割部分とグローバル部分(両方)には、区切り文字を指定できる分割演算子もあります。shksh$=string$~string$=~string

array=(${(s:_:)string})

または空の要素を保持します。

array=("${(@s:_:)string}")

ありますs分ける、いいえ定義する$IFS(また、既知のPOSIX不適合もありますzsh。)split()空の文字列が1以外のゼロ要素に分割される点で、JavaScriptとは異なります。

-splittingとの注目すべき違いの1つは、$IFS文字列${(s:abc:)string}で分割が発生するのabcに対し、、を使用すると、またはでIFS=abc分割されることです。abc

zshそして、ksh93空白、タブ、または改行文字の特殊処理を2倍にすることで削除できます$IFS

歴史的に、Bourneシェル(援助または最新の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" '[_+]+'))"

シェルにはzshPerl準拠の正規表現のサポートが組み込まれていますが(zsh/pcreモジュールに)、これを使用して文字列を分割するのは比較的面倒です。

答え2

はい、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

読む

-ㅏ名前

単語はゼロから始まり、配列変数anameの順次インデックスに割り当てられます。 aname は、新しい値が割り当てられる前に設定解除されます。他の名前パラメータは無視されます。

IFS

内部フィールド区切り文字は、拡張後の単語分割と読み込み組み込みコマンドを使用して行を単語に分割するために使用されます。デフォルトは「」です。

read最初の改行文字で停止します。を渡すことで-d ''これをread防ぐことができますが、この場合、演算子は最後に追加の改行を引き起こします<<<。手動で削除できます。

IFS='_' read -r -d '' -a array <<< "$r"
array[$((${#array[@]}-1))]=${array[$((${#array[@]}-1))]%?}

関連情報