26

いつパイプするかを明確にしたい | またはリダイレクト < > はコマンドで優先されますか?

これは私の考えですが、確認が必要です。これがどのように機能するかです。

例 1:

sort < names | head
The pipe runs first:  names|head   then it sorts what is returned from names|head

例 2:

ls | sort > out.txt
This one seems straight forward by testing, ls|sort then redirects to out.txt

例 3:

Fill in the blank?  Can you have both a < and a > with a | ???
4

5 に答える 5

28

構文のグループ化に関しては、優先順位が高くなります><つまり、次の 2 つのコマンドは同等です。

sort < names | head
( sort < names ) | head

次の 2 つも同様です。

ls | sort > out.txt
ls | ( sort > out.txt )

ただし、順序付けに関しては、|最初に実行されます。したがって、このコマンド:

cat in.txt > out1.txt | cat > out2.txt

out1.txtはではなくに入力されます。out2.txtこれは、 が の> out1.txt実行され、その代わりに使用されるためです (出力は にパイプされません)。|cat > out2.txt

同様に、次のコマンド:

cat < in1.txt | cat < in2.txt

in2.txtではなくを出力します。これはin1.txt、 が の< in2.txt実行され、それを置き換えるためです (したがって、 からの入力はパイプされません)。|cat < in1.txt

于 2012-10-17T19:45:40.193 に答える
13

からman bash(他の引用と同様に):

SHELL GRAMMAR
   Simple Commands
       A simple command is a sequence of optional variable assignments followed by
       blank-separated words and redirections, and terminated  by  a  control
       operator. The first word specifies the command to be executed, and is
       passed as argument zero.  The remaining words are passed as arguments
       to the invoked command.

       The return value of a simple command is its exit status, or 128+n if
       the command is terminated by signal n.

   Pipelines
       A pipeline is a sequence of one or more commands separated by one of
       the control operators | or |&.  The format for a pipeline is:

              [time [-p]] [ ! ] command [ [|⎪|&] command2 ... ]

言い換えれば、(単純な) コマンドに対して任意の数のリダイレクトを行うことができます。これをパイプラインの一部として使用することもできます。別の言い方をすれば、リダイレクトはパイプよりも強く結合します。

これを回避するには、いくつかの方法があります (ただし、これらが必要または美的であることはめったにありません)。

1.「複合コマンド」を作成して、それにリダイレクトできます。

 Compound Commands
   A compound command is one of the following:

   (list)  list is executed in a subshell environment (see
           COMMAND EXECUTION ENVIRONMENT below).  Variable
           assignments  and  builtin  commands  that  affect  the
           shell's environment do not remain in effect after the
           command completes.  The return status is the exit status of list.

   { list; }
          list  is  simply  executed  in the current shell environment.  list
          must be terminated with a newline or semicolon.  This is known as a
          group command. The return status is the exit status of list.  Note
          that unlike the metacharacters ( and ), { and } are reserved words
          and must occur where a reserved word is permitted to be recognized.
          Since they do not cause a word break, they must be separated from
          list by whitespace or another shell metacharacter.

そう:

$ echo foo > input
$ { cat | sed 's/^/I saw a line: /'; } < input
I saw a line: foo

2.「プロセス置換」を使用してパイプにリダイレクトできます。

Process Substitution
   Process  substitution  is  supported on systems that support named pipes
   (FIFOs) or the /dev/fd method of naming open files.  It takes the form of
   <(list) or >(list).  The process list is run with its input or output
   connected to a FIFO or some file in /dev/fd.  The name of this file is
   passed as  an  argument  to  the  current  command  as the result of the
   expansion.  If the >(list) form is used, writing to the file will provide
   input for list.  If the <(list) form is used, the file passed as an argument
   should be read to obtain the output of list.

そう:

 rici@...$ cat > >(sed 's/^/I saw a line: /') < <(echo foo; echo bar)
 I saw a line: foo
 rici@...$ I saw a line: bar

(出力が終了する前にプロンプ​​トが表示される理由と、その対処方法は演習として残します)。

于 2012-10-17T20:07:48.237 に答える
6

これは、いくつか読んだ後に私が理解していることのほとんどです(ruakhの回答を含む)

まず、複数回リダイレクトすると、すべてのリダイレクトが実行されますが、最後のリダイレクトのみが有効になります (以前のリダイレクトでエラーが発生しないと仮定します)。

  • cat < in1.txt < in2.txtが存在しない場合、このコマンドは失敗します (cat < in2.txtが最初に実行されるため) 。in1.txt< in1.txt

  • 同様に、 withcat in.txt > out1.txt > out2.txtには の内容のみout2.txtが含まれますがout2.txt、 が> out1.txt最初に実行されたため、out1.txt存在しない場合は が作成されます。

パイプが行うことはstdout、前のコマンドをstdin次のコマンドに接続することであり、その接続は他のリダイレクトの前に行われます(Bashマニュアルから)。

だからあなたは考えることができます

cat in1.txt > out1.txt | cat > out2.txt

なので

cat in1.txt > pipe > out1.txt; cat < pipe > out2.txt

前述の複数のリダイレクト ルールを適用すると、これを次のように単純化できます。

cat in1.txt > out1.txt; cat < pipe > out2.txt

結果: には何も書き込まれていないため、の内容in1.txtが にコピーされます。out1.txtpipe


[ruakh][3]の別の例を使用すると、
cat < in1.txt | cat < in2.txt

とほぼ同等です

cat > pipe < in1.txt; cat < pipe < in2.txt

これは効果的に

cat > pipe < in1.txt; cat < in2.txt

結果: 今回は に何かが書き込まれますpipeが、2 番目はではなくcatから読み取られるため、 の内容のみが出力されます。が同じ側 (または) のリダイレクトの途中にある場合、それは無視されます。in2.txtpipein2.txtpipe><

于 2012-10-18T03:34:13.410 に答える
3

好きな場所に配置するのは少し非正統的ですが、完全に合法<です。そのため、左から右へのデータフローをよりよく示しているため、これを好みます。

<input.txt sort | head >output.txt

これを行うことができないのは、組み込みの制御構造コマンド ( forifwhile) を使用する場合のみです。

# Unfortunately, NOT LEGAL
<input.txt  while read line; do ...; done

これらはすべて同等のコマンドですが、混乱を避けるために、最初または最後のコマンドのみを使用する必要があります。

<input.txt grep -l foobar
grep <input.txt -l foobar
grep -l <input.txt foobar
grep -l foobar <input.txt

ファイル名は常にリダイレクト演算子の直後に来る必要があるため、私は<とファイル名の間の任意のスペースを省くことを好みます。

于 2012-10-20T20:56:47.333 に答える
1

訂正:

例 1:

sort < names | head

この場合、最初に入力リダイレクトが実行され (名前がソートされます)、次にその結果がパイプでヘッドに渡されます。

一般的には、左から右に読むことができます。標準イディオムは次のように機能します。

  • 入力リダイレクトの使用 "<" は、プログラムが stdin ではなくファイルから読み取ることを示します
  • 出力リダイレクトの使用 ">" は、標準出力ではなくファイルに出力するようにプログラムに指示します
  • パイプ "program_a | program_b" を使用すると、通常は program_a によって stdout に出力されるすべてのものを取得し、stdin から読み取ったかのようにすべてを program_b に直接フィードします。
于 2012-10-17T19:42:06.293 に答える