プログラム引数を分離する方法を決定するには?

プログラム引数を分離する方法を決定するには?

killユーティリティが空白文字と改行文字で区切られた引数を受け入れることができることを確認しました。

$ sleep 120 & sleep 240 &
[1] 75341
[2] 75342
$ /bin/kill $(echo "75341 75342")
[1]-  Terminated: 15          sleep 120
[2]+  Terminated: 15          sleep 240
$ sleep 120 & sleep 240 &
[1] 75577
[2] 75578
$ /bin/kill $(echo -e "75577\n75578")
[1]-  Terminated: 15          sleep 120
[2]+  Terminated: 15          sleep 240
$ 

たとえば、改行で区切られたパラメータを許可した場合、ユーティリティ自体によって異なりますか?

答え1

引用しなかったので、$(echo -e "75577\n75578")これを処理することはシェルに依存します。

シェルが取得した内容を解析する方法は、内部フィールド区切り記号(IFS)という変数によって異なります。デフォルトでは、スペース、タブ、改行文字が含まれています。つまり、これら3文字の組み合わせは、引数間の有効な区切り文字と見なされます。

改行を含まない文字列に設定すると、コマンドを\n含むパラメータを受け取り、失敗します。

$ touch a b
$ echo "$IFS" | od -c
0000000      \t  \n  \n
0000004$ 
$ ls -l a b
-rw-r--r-- 1 jlliagre jlliagre 0 Nov 12 15:04 a
-rw-r--r-- 1 jlliagre jlliagre 0 Nov 12 15:04 b
$ ls -l $(printf "a\nb")
-rw-r--r-- 1 jlliagre jlliagre 0 Nov 12 15:05 a
-rw-r--r-- 1 jlliagre jlliagre 0 Nov 12 15:05 b
$ IFS=" "
$ ls -l $(printf "a\nb")
ls: cannot access a
b: No such file or directory
$

答え2

ユーティリティのパラメータは次のとおりです。文字列リスト、単一の文字列ではありません。したがって、ユーティリティには引数の間に区切り記号の概念はありません。パラメータはリストの個々の要素にすぎず、間には何もありません。

文字列をパラメータリストに分割するエンティティはシェルです。シェルは/bin/kill $(echo "75341 75342")実行と同様にコマンドラインを実行します。シリーズ拡張。具体的には:

  1. コマンドはトークンで区切られます。このルールについて詳しく説明しません。トークンは、基本的に最上位のスペースを含まない句読点または文字シーケンスです。ここでトークンは文字列/bin/killとコマンドの置換であり$(echo "75341 75342")、それ自体は$(…)演算子とトークンでecho構成されています75341 75342
  2. コマンド置換演算子でコマンドを実行します。これは、コマンド名echoと単一のパラメータを使用する簡単なコマンドです75341 75342。 (引用符はシェル構文の一部であり、コマンドの引数となる文字列を区切ります。)
  3. このコマンドの出力は75341 75342␤newlineです。シェルはこの出力を取り、最後の改行文字を削除して文字列を生成します75341 75342
  4. コマンド置換演算子はリストコンテキスト(二重引用符を除く)で使用されるため噴射そしてファイル名拡張子。単語分割には、文字列を取得して変数の値に基づいて文字列リストに分割することが含まれますIFS。デフォルトでは、IFSスペース、タブ、および改行が含まれるため、文字列はこれらの文字の順序に関係なく分割されます。 2つの文字列75341の合計リストになります75342。ファイル名拡張子はここで何も変更しません。
  5. /bin/kill今、75341そして3つの文字列を含むリストがあります75342。これは/bin/kill2つの引数とを使用して75341コマンドとして実行されます75342

コマンドを使用すると、/bin/kill $(echo -e "75577\n75578")拡張子はほぼ同じです。ステップ3では、出力が生成されます75341␤75342␤。手順4では、改行とスペースは同じ有効な単語区切り文字であるため、単語75341分割によって以前と同じリストが生成されます。75342したがって、手順5ではまったく同じコマンドを実行します。

ご覧のとおり、引数の分離を決定するステップは、シェルで実行されるトークン化ステップです。値を変更してこの手順を試すことができますIFS。たとえば、次は同じコマンドを再生成します。

IFS=+
/bin/kill $(echo "75341+75342")

答え3

$( )行を空白に変える仕組みだと思います。ただ使用してくださいecho $(echo -e "75577\n75578")

今試してみてください

cat <<EOF | kill
1234
5678
EOF

(適切な値で)。

答え4

これは完全にに関するものではありませんkill。 (つまり)を使用しても、ls次のような動作が発生します。

> touch file1 file2
> ls $(echo -e "file1 file2")
file1 file2
> ls $(echo -e "file1\nfile2")
file1 file2

これは、コマンド自体とは関係がなく、bashがスクリプトを処理する方法に関連しているためです。 「スクリプト」の観点から見ると、私の言葉はより明確になります。コマンドをファイルにリダイレクトし、chmodを777として実行したら、次のようにします。

> touch file1 file2
> ls $(echo -e "file1\nfile2")
file1 file2
> echo -e 'ls $(echo -e "file1\nfile2")' > tryme.sh
> cat tryme.sh
ls $(echo -e "file1
file2")
> chmod 777 tryme.sh
> ./tryme.sh
file1 file2

関連情報