bashの<<、<<、<<の違いは何ですか?


102

違いは何だ<<<<<< <bashのでは?


20
少なくともこれらのGoogle中心の時代では、これらの記号ベースの演算子を検索することは困難です。「<< <<< <<」をプラグインして、何か便利なものを入手できる検索エンジンはありますか
ダニエル・グリスコム

11
@DanielGriscomありますSymbolHoundが
デニス

1
@DanielGriscom Stack Exchangeは、以前はシンボルの検索をサポートしていましたが、その後何かが壊れて、誰も修正しませんでした。
ムル

それはすでにそこにあります(そしてほぼ1年の間):シェルの制御およびリダイレクト演算子は何ですか?
スコット

回答:


115

ヒアドキュメント

<<here-document構造として知られています。プログラムに終了テキストを知らせ、その区切り文字が表示されるたびに、プログラムは入力としてプログラムに与えたすべてのものを読み取り、タスクを実行します。

ここに私が意味するものがあります:

$ wc << EOF
> one two three
> four five
> EOF
 2  5 24

この例ではwcEOF文字列を待機するようにプログラムに指示し、5つの単語EOFを入力してから、入力を完了したことを示すために入力します。実際には、wc単独で実行し、単語を入力してから押すのに似ていますCtrlD

bashではこれらは一時ファイルを介して、通常はの形式/tmp/sh-thd.<random string>で実装されますが、ダッシュでは匿名パイプとして実装されます。これは、straceコマンドでシステムコールをトレースすることで確認できます。と置き換えbashsh/bin/shこのリダイレクトの実行方法を確認します。

$ strace -e open,dup2,pipe,write -f bash -c 'cat <<EOF
> test
> EOF'

ここに文字列

<<<として知られていhere-stringます。テキストを入力する代わりに、事前に作成したテキストの文字列をプログラムに渡します。たとえば、そのような特定のケースの出力を取得するためにbcできるようなプログラムではbc <<< 5*4、bcをインタラクティブに実行する必要はありません。

bashのヒア文字列は一時ファイルを介して実装され、通常/tmp/sh-thd.<random string>は後でリンク解除される形式であるため、一時的にメモリ領域を占有し/tmpますが、ディレクトリエントリのリストには表示されず、匿名ファイルとして効果的に存在します。シェル自体によってファイル記述子を介して参照され、そのファイル記述子はコマンドによって継承され、後でdup2()関数を介してファイル記述子0(stdin)に複製されます。これは次の方法で確認できます

$ ls -l /proc/self/fd/ <<< "TEST"
total 0
lr-x------ 1 user1 user1 64 Aug 20 13:43 0 -> /tmp/sh-thd.761Lj9 (deleted)
lrwx------ 1 user1 user1 64 Aug 20 13:43 1 -> /dev/pts/4
lrwx------ 1 user1 user1 64 Aug 20 13:43 2 -> /dev/pts/4
lr-x------ 1 user1 user1 64 Aug 20 13:43 3 -> /proc/10068/fd

そして、(出力が読みやすくするために短縮システムコールのトレースを介して、一時ファイルがFD 3、そこに書き込まれたデータは、それがで再開放されるように開放されている様子がわかりO_RDONLY、その後、FD 4としてフラグ以降リンク解除dup2()によって継承されたFD 0に、cat後で):

$ strace -f -e open,read,write,dup2,unlink,execve bash -c 'cat <<< "TEST"'
execve("/bin/bash", ["bash", "-c", "cat <<< \"TEST\""], [/* 47 vars */]) = 0
...
strace: Process 10229 attached
[pid 10229] open("/tmp/sh-thd.uhpSrD", O_RDWR|O_CREAT|O_EXCL, 0600) = 3
[pid 10229] write(3, "TEST", 4)         = 4
[pid 10229] write(3, "\n", 1)           = 1
[pid 10229] open("/tmp/sh-thd.uhpSrD", O_RDONLY) = 4
[pid 10229] unlink("/tmp/sh-thd.uhpSrD") = 0
[pid 10229] dup2(4, 0)                  = 0
[pid 10229] execve("/bin/cat", ["cat"], [/* 47 vars */]) = 0
...
[pid 10229] read(0, "TEST\n", 131072)   = 5
[pid 10229] write(1, "TEST\n", 5TEST
)       = 5
[pid 10229] read(0, "", 131072)         = 0
[pid 10229] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=10229, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++

意見:ここでの文字列は一時テキストファイルを使用するため、POSIX定義によるテキストファイルは改行文字で終わる行を持たなければならないため、ヒア文字列が常に末尾の改行を挿入する理由が考えられます。

プロセス置換

以下のようtldp.orgは説明して、

プロセス置換は、1つまたは複数のプロセスの出力を別のプロセスの標準入力に送ります。

それで、実際にこれは1つのコマンドのstdoutを他に配管するのと同様echo foobar barfoo | wcです、例えば。ただし、bashのマンページでは、と表示されていることに注意してください<(list)。したがって、基本的には複数の(!)コマンドの出力をリダイレクトできます。

注:技術的に< <は、1つのことではなく、<からの出力のシングルリダイレクトとプロセスリダイレクトの2つのリダイレクトを指していると言います <( . . .)

置換を処理するだけの場合はどうなりますか?

$ echo <(echo bar)
/dev/fd/63

ご覧のとおり、シェルは/dev/fd/63出力が行く一時ファイル記述子を作成します(Gillesの答えによれば、これは匿名パイプです)。つまり <、そのファイル記述子をコマンドへの入力としてリダイレクトします。

したがって、非常に単純な例では、2つのエコーコマンドからの出力をwcにプロセス置換します。

$ wc < <(echo bar;echo foo)
      2       2       8

そのため、ここでは、シェルで括弧内で発生するすべての出力用のファイル記述子を作成し、それを入力としてリダイレクトします。wc予想どおり、wcは2つのエコーコマンドからそのストリームを受け取ります。適切には、2単語、2行、6文字に加えて2つの改行がカウントされます。

サイドノート:プロセス置換は、bashism(のような高度なシェルで使用可能なコマンドまたは構造ですbashが、POSIXでは指定されていません)と呼ばれる場合がありますがkshkshのマニュアルページおよびこの回答が示唆するように、bashが存在する前に実装されていました。以下のようなシェルtcshmkshしかし、プロセス置換を持っていません。では、プロセスを置換せずに、複数のコマンドの出力を別のコマンドにリダイレクトするにはどうすればよいでしょうか?グループ化とパイピング!

$ (echo foo;echo bar) | wc
      2       2       8

事実上、これは上記の例と同じですがwc 、パイプリンクされたサブシェル全体とstdinのstdoutを作成するため、これはプロセス置換とはまったく異なります。一方、プロセス置換は、コマンドに一時ファイル記述子を読み取らせます。

パイプでグループ化できるのに、なぜプロセス置換が必要なのですか?時には配管が使えないからです。以下の例を検討してください-2つのコマンドの出力を比較しますdiff(2つのファイルが必要です。この場合、2つのファイル記述子を与えています)

diff <(ls /bin) <(ls /usr/bin)

7
< <プロセス置換からstdinを得ているときに使用されます。このようなコマンドは次のようになりますcmd1 < <(cmd2)。たとえば、wc < <(date)
-John1024

4
はい、プロセス置換はbash、zsh、AT&T ksh {88,93}で
ジョン1024

2
< < それ自体は物ではなく、プロセス置換の場合は、<その後に続く何かが偶然に続くだけです<
-immibis

1
@muru私の知る限りで<<<は、最初にPlan 9 rcシェルのUnixポートによって実装され、その後zsh、bash、およびksh93によって採用されました。私はそれをバシズムとは呼びません。
jlliagre

3
配管が使用できない場合の別の例は:echo 'foo' | read; echo ${REPLY}ではない返すfooので、readサブシェルで開始された-配管は、サブシェルを起動します。ただし、read < <(echo 'foo'); echo ${REPLY}サブシェルfooがないため、は正しく返されます。
水田ランダウ

26

< < 構文エラーです:

$ cat < <
bash: syntax error near unexpected token `<'

< <()あるプロセス置換<()リダイレクションと組み合わせる)は、( <):

不自然な例:

$ wc -l < <(grep ntfs /etc/fstab)
4
$ wc -l <(grep ntfs /etc/fstab)
4 /dev/fd/63

プロセス置換では、ファイル記述子へのパスがファイル名のように使用されます。ファイル名を直接使用したくない(または使用できない)場合は、プロセス置換とリダイレクトを組み合わせます。

明確にするために、< <演算子はありません。


私はあなたの答えで、<<()よりも<<()より便利ですか?
ソルフィッシュ

1
@solfish <()はファイル名のようなものを与えるので、より一般的には便利です- < <()必要でないかもしれないstdinを置き換えることです。ではwc、後者の方がより便利です。これは、他の場所ではあまり有用であるかもしれない
muru

12

< <は構文エラーです。おそらく、command1 < <( command2 )これは単純な入力リダイレクトとそれに続くプロセス置換であり、非常に似ていますが、同等ではありません。

command2 | command1

あなたが実行していると仮定すると違いがbashありcommand1、それが最初のもので、現在のシェル内で実行される間に、第2の場合ではサブシェルで実行されます。つまり、設定された変数command1は、プロセス置換バリアントを使用しても失われません。


11

< <構文エラーが発生します。適切な使用は次のとおりです。

例の助けを借りて説明する:

< <()

while read line;do
   echo $line
done< <(ls)

上記の例では、whileループへの入力はlsコマンドからecho取得されます。このコマンドは、1行ずつ読み取り、ループ内で編集できます。

<()プロセス置換に使用されます。詳細と例について<()は、次のリンクをご覧ください。

プロセス置換とパイプ

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.