echo> 1 2 3はなぜコンテンツ2 3の1というファイルを生成するのですか?

echo> 1 2 3はなぜコンテンツ2 3の1というファイルを生成するのですか?
$ echo > 1 2 3; ls -latr 1; cat 1
-rw-rw-r-- 1 kahn kahn 4 Jun 23 14:05 1
2 3

これはリダイレクト評価に関連していますか>?だから:

echo > 1 2 3

技術的には、次のように書き直すこともできます。

echo 2 3 > 1

IOリダイレクトの作業順序と評価方法をよりよく理解するのに役立つリソースはありますか?この例が役に立たないか一般的ではないかもしれないことは認めますが、ここで正確に何が起こっているのかをよりよく理解したいと思います。

答え1

参照できる適切なリソースはPOSIXです。シェル構文、単純なコマンドを次のように定義します。

simple_command   : cmd_prefix cmd_word cmd_suffix
                 | cmd_prefix cmd_word
                 | cmd_prefix
                 | cmd_name cmd_suffix
                 | cmd_name
                 ;

ここで最も関連性の高い部分は次の定義ですcommand_suffix

cmd_suffix       :            io_redirect
                 | cmd_suffix io_redirect
                 |            WORD
                 | cmd_suffix WORD
                 ;

これは再帰的であるため、リダイレクトパラメータとコマンドパラメータは任意の順序で表示できます。

また、POSIX は以下を定義します。リダイレクト構文〜のように

[n]redir-op word

nオプションの数字とリダイレクト演算子(>あなたの場合)の間にスペースは使用できませんが、リダイレクト演算子と次の単語の間にスペースは使用できます。拡張されるとword1あなたの場合)は、ストリームが配信される(またはソースから)ファイルの名前として使用されます。

したがって、文を書くのも合法だ。

$ echo  > 1  foo  bar
# ^^^^  ^^^^^^^^^^^^^
#  \     \
#   \     cmd_suffix
#    \  ^^^  ^^^  ^^^
#     \  \    \    \
#      \  \    \    WORD
#       \  \    WORD
#        \  io_redirect
#         cmd_name

または

$ echo foo >1 bar

でも

$ echo > 1 foo > 1 bar > 1

(もちろん繰り返しは> 1何の意味もありません。)

完全性を期すために、定義cmd_prefix自体simple_commandは再帰的に定義されます。

cmd_prefix       :            io_redirect
                 | cmd_prefix io_redirect
                 |            ASSIGNMENT_WORD
                 | cmd_prefix ASSIGNMENT_WORD
                 ;

これは、リダイレクトと変数の割り当てが任意の順序でコマンドの前に表示されることを意味します。

たとえば、次のようにできます。

$ LC_ALL=C <infile sort >outfile 2>errfile
# ^^^^^^^^^^^^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^
#       \            \           \
#   cmd_prefix    cmd_word   cmd_suffix

または

$ 2>errfile >outfile <infile LC_ALL=C sort

または

$ LC_ALL=C sort <infile 2>errfile >outfile

これらはすべて同じように有効ですが、リダイレクト、変数の割り当て、および拡張は左から右に行われ、順序が関連する可能性があることを覚えておく必要があります(infile存在しない場合はoutfile切り捨てられませんcat <infile >outfilecat >outfile <infile

答え2

単語はスペースで区切られます。引用符付き文字列は、スペースに関係なく単一の単語として扱われます。変数の値は、使用されるときのトークン化の候補です(これが通常、変数名を二重引用符で囲むのが最善の理由です"$var")。

リダイレクト演算子は、次の単一の単語を使用します。

詳細については、シェルのマニュアルページ(man bash「拡張」の下など)で確認できます。

拡張順序は、中かっこ拡張、チルダ拡張、パラメータ、変数と算術拡張、コマンド置換(左から右へ)、トークン化、パス名拡張です。

関連情報