これをどうやって行うべきかを提案し、その理由を説明しますが、最初に何か他のことについてお話したいと思います...
set -- 'Arg 1: Line 1.' \
'Arg 2: Line 2.' \
'and so on for' \
'as long as you might like.'
var="$*"
ここで提供されている他の多くのソリューションは、展開方法を変更することにより、シェル変数の内容に何らかの形で影響を与えることができることを示唆しているようです。これは事実ではないことを保証できます。
string="some stuff here \
some more stuff here."
echo $string ${#string}
echo "$string" "${#string}"
出力
some stuff here some more stuff here. 53
some stuff here some more stuff here. 53
上記の内容は、最初にフィールド分割展開、次に展開のソース変数のバイト数に関するレポート、次に引用符で区切られた展開、および同じバイト数です。出力は異なる場合がありますが、シェル変数の内容は$string
割り当て時を除いてまったく変化しません。
さらに、これがなぜなのか理解していないと、非常に厄介な驚きにすぐに遭遇することになります。少し条件を変えて、もう一度試してみましょう。
IFS=sf
echo $string ${#string}
echo "$string" "${#string}"
同じ$string
-異なる環境。
出力
ome tu here ome more tu here. 53
some stuff here some more stuff here. 53
フィールド分割は、で定義されたフィールド区切り文字に基づいて発生し$IFS
ます。区切り$IFS
文字には、空白と$IFS
その他の2種類があります。デフォルトで$IFS
は、値スペースのタブ改行が割り当てられ$IFS
ます。これは、3つの可能な空白値です。ただし、上記のように簡単に変更でき、フィールド分割拡張に大きな影響を与える可能性があります。
$IFS
空白はシーケンスによって単一のフィールドに移動します。これはecho
、スペースを$IFS
含むときにスペースのシーケンスを含む展開が単一のスペースのみと評価される理由echo
です。これは、スペースで引数を連結するためです。しかし、空白以外の値は同じように変化せず、発生する区切り文字のそれぞれは常にフィールドを取得します- 上記のもので見られるように。
これは最悪ではありません。この他を検討してください$string
。
IFS=$space$tab$newline
cd emptydir
string=" * * * \
* * * "
echo $string ${#string}
echo "$string" "${#string}"
出力
* * * * * * 30
* * * * * * 30
良さそうですね。さて、もう一度環境を変えましょう。
touch file1 file2 file3 file4 file5
echo $string ${#string}
echo "$string" "${#string}"
出力
file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 30
* * * * * * 30
わあ
デフォルトでは、シェルはファイル名が一致する場合、ファイル名を展開します。これは、パラメーターの展開と解析順序のフィールド分割の後に発生するため、引用符で囲まれていない文字列はこの方法で脆弱です。set -f
必要に応じてこの動作をオフに切り替えることができますが、POSIX互換シェルはデフォルトで常にglobになります。
これは、インデントの設定に合わせて展開に引用符をドロップするときに直面する種類です。$string
それでも、どのような場合でも、展開動作に関係なく、実際の値は常に最後に割り当てたときの値のままです。それでは、最初の話に戻りましょう。
set -- 'Arg 1: Line 1.' \
'Arg 2: Line 2.' \
'and so on for' \
'as long as you might like.'
var="$*"
echo "$var" "${#var}"
出力
Arg 1: Line 1. Arg 2: Line 2. and so on for as long as you might like. 70
これは、シェル構文をインデント設定に適合させるはるかに安全な方法だと思います。上記で行っていることは、個々の文字列を位置パラメータに割り当てます。位置パラメータは、$1
orなどの数字で参照できます。${33}
次に、連結値を$var
特別なシェルパラメータを使用して割り当てます$*
。
このアプローチは$IFS
、たとえそうであっても影響を受けません。それでも、私$IFS
はこの点で追加の利益との関係を検討します。考慮してください:
IFS=\ ;space_split="$*"
IFS=/; slash_split="$*";IFS='
';new_line_split="$*"
echo "$space_split"
echo "$slash_split"
echo "$new_line_split"
出力
Arg 1: Line 1. Arg 2: Line 2. and so on for as long as you might like.
Arg 1: Line 1./Arg 2: Line 2./and so on for/as long as you might like.
Arg 1: Line 1.
Arg 2: Line 2.
and so on for
as long as you might like.
ご覧のとおり、の最初のバイトで$*
各引数を連結"$@"
し$IFS
ます。そのため、$IFS
異なる割り当てが行われている間に値を保存すると、保存された値ごとに異なるフィールド区切り文字が取得されます。ちなみに、上の図は各変数のリテラル値です。区切り文字がまったく必要ない場合は、次のようにします。
IFS=;delimitless="$*"
echo "$delimitless" "${#delimitless}"
出力
Arg 1: Line 1.Arg 2: Line 2.and so on foras long as you might like. 67