さまざまなコマンドをさまざまなシンボルに接続するチュートリアルをオンラインでよく見ます。例えば:
command1 | command2
command1 & command2
command1 || command2
command1 && command2
他のものはコマンドをファイルに接続しているようです:
command1 > file1
command1 >> file1
これは何だ?彼らは何と呼ばれている?彼らは何をしますか?それらはもっとありますか?
これらはシェルオペレーターと呼ばれ、そうです。 2つの主要なクラス 制御演算子 および リダイレクト演算子 の間で最も一般的なものの概要と、bashシェルに関してそれらがどのように機能するかを簡単に説明します。
シェルコマンド言語で、制御機能を実行するトークン。
以下の記号のいずれかです。_& && ( ) ; ;; <newline> | ||
_
そしてbashでは_|&
_です。
_!
_は制御演算子ではありませんがですが、 予約語 です。 算術式 内およびテスト構成内で論理NOT [否定演算子]になります(スペース区切りが必要です)。
_;
_:最初のコマンドの結果に関係なく、次のコマンドが終了した後に実行します。
_command1 ; command2
_
最初に_command1
_がフォアグラウンドで実行され、終了すると_command2
_が実行されます。
文字列リテラルにない、または特定のキーワードの後にない改行は、セミコロン演算子とnotは同等です。 _;
_で区切られた単純なコマンドのリストは、まだlistです。シェルのパーサーでは、_;
_に続く単純なコマンドを引き続き読み取る必要があります。実行前に区切られた単純なコマンドですが、改行はコマンドリスト全体またはリストのリストを区切ることができます。違いは微妙ですが複雑です。シェルに改行に続くデータを読み取るための以前の必須事項がない場合、改行は、シェルがすでに読み取った単純なコマンドの評価を開始できるポイントをマークしますが、_;
_セミコロンにはありません。
_&
_:これはバックグラウンドでコマンドを実行し、同じシェルで作業を続行できるようにします。
_ command1 & command2
_
ここでは、_command1
_がバックグラウンドで起動され、_command2
_が終了するのを待たずに、_command1
_がフォアグラウンドですぐに実行を開始します。
_command1
_の後の改行はオプションです。
_&&
_:ANDリストを作成するために使用され、別のコマンドが正常に終了した場合にのみ、1つのコマンドを実行できます。
_ command1 && command2
_
ここでは、_command2
_は、_command1
_が完了した後に実行され、_command1
_が成功した場合(終了コードが0の場合)はonlyになります。どちらのコマンドもフォアグラウンドで実行されます。
このコマンドはまた書くことができます
_if command1
then command2
else false
fi
_
戻りステータスが無視される場合は、単に_if command1; then command2; fi
_。
_||
_:ORリストを作成するために使用され、別のコマンドが正常に終了しなかった場合にのみ、1つのコマンドを実行できます。
_ command1 || command2
_
ここで、_command2
_は、_command1
_が失敗した場合にのみ実行されます(0以外の終了ステータスを返した場合)。どちらのコマンドもフォアグラウンドで実行されます。
このコマンドはまた書くことができます
_if command1
then true
else command2
fi
_
または短い方法で_if ! command1; then command2; fi
_。
_&&
_および_||
_は左結合です。詳細については、 シェルの論理演算子の優先順位&&、 を参照してください。
_!
_:これは「not」演算子として機能する予約語ですが、コマンドの戻りステータスを否定するために使用されます—コマンドがゼロ以外のステータスを返す場合は0を返し、次の場合は1を返しますステータス0を返します。また、test
ユーティリティの論理NOT。
_! command1
[ ! a = a ]
_
そして、算術式内の真のNOT演算子:
_$ echo $((!0)) $((!23))
1 0
_
_|
_:パイプ演算子。1つのコマンドの出力を別のコマンドの入力として渡します。パイプ演算子から作成されたコマンドは pipeline と呼ばれます。
_ command1 | command2
_
_command1
_によって出力される出力は、_command2
_への入力として渡されます。
_|&
_:これは、bashおよびzshでの_2>&1 |
_の短縮形です。 1つのコマンドの標準出力と標準エラーの両方を別のコマンドの入力として渡します。
_command1 |& command2
_
_;;
_は、単に caseステートメント の終わりを示すために使用されます。 Ksh、bash、およびzshは、次のケースにフォールスルーする_;&
_と、後続のケースを続行してテストする_;;&
_(ATT kshにはない)もサポートします。
_(
_および_)
_は グループコマンド に使用され、サブシェルで起動します。 _{
_および_}
_もコマンドをグループ化しますが、サブシェルでは起動しません。シェル構文のかっこ、角かっこ、中かっこのさまざまな種類の説明については、 この答え を参照してください。
シェルコマンド言語で、リダイレクト機能を実行するトークン。次の記号のいずれかです。
_< > >| << >> <& >& <<- <>
_
これらにより、コマンドの入力と出力を制御できます。それらは、単純なコマンド内のどこにでも表示でき、コマンドの後に続く場合もあります。リダイレクションは、左から右に表示される順序で処理されます。
_<
_:コマンドに入力を与えます。
_command < file.txt
_
上記は_file.txt
_の内容に対してcommand
を実行します。
_<>
_:上記と同じですが、ファイルはread-onlyではなくread + writeモードで開かれます。
_command <> file.txt
_
ファイルが存在しない場合は作成されます。
コマンドは通常、標準入力からreadのみであるため、ほとんど使用されません。ただし、 特定の状況で便利です です。
_>
_:コマンドの出力をファイルに送信します。
_command > out.txt
_
上記は、command
の出力を_out.txt
_として保存します。ファイルが存在する場合はその内容が上書きされ、存在しない場合は作成されます。
この演算子は、何かを 標準エラー または 標準出力 に出力するかどうかを選択するためにもよく使用されます。
_command >out.txt 2>error.txt
_
上記の例では、_>
_は標準出力をリダイレクトし、_2>
_は標準エラーをリダイレクトします。出力は_1>
_を使用してリダイレクトすることもできますが、これはデフォルトなので、_1
_は通常省略され、単に_>
_と記述されます。
したがって、command
を_file.txt
_で実行し、その出力を_out.txt
_に保存し、エラーメッセージを_error.txt
_に保存するには、次のように実行します。
_command < file.txt > out.txt 2> error.txt
_
_>|
_:_>
_と同じように動作しますが、シェルが上書きを拒否するように構成されている場合でも、ターゲットを上書きします(_set -C
_または_set -o noclobber
_を使用)。
_command >| out.txt
_
_out.txt
_が存在する場合、command
の出力がその内容を置き換えます。存在しない場合は作成されます。
_>>
_:ターゲットファイルが存在する場合に新しいデータが追加されることを除いて、_>
_と同じです。
_command >> out.txt
_
_out.txt
_が存在する場合、command
の出力は、すでにそこにあるものの後に追加されます。存在しない場合は作成されます。
_&>
_、_>&
_、_>>&
_および_&>>
_:(非標準)。標準エラーと標準出力の両方をリダイレクトし、それぞれ置換または追加します。
_command &> out.txt
_
command
の標準エラーと標準出力の両方が_out.txt
_に保存され、その内容が上書きされるか、存在しない場合は作成されます。
_command &>> out.txt
_
上記のように、_out.txt
_が存在する場合を除いて、command
の出力とエラーがそれに追加されます。
_&>
_バリアントはbash
に由来し、_>&
_バリアントはcsh(数十年前)に由来します。これらは両方とも他のPOSIXシェルオペレーターと競合するため、移植可能なsh
スクリプトでは使用しないでください。
_<<
_:ヒアドキュメント。複数行の文字列を印刷するためによく使用されます。
_ command << Word
Text
Word
_
ここで、command
は、上記の例でWord
、Text
が次に出現するまで、すべてを入力として使用します。 Word
は、多くの場合EoF
またはそのバリエーションですが、任意の英数字の文字列(だけでなく)にすることができます。 Word
が引用符で囲まれている場合、ヒアドキュメントのテキストは文字どおりに扱われ、展開は実行されません(変数など)。引用符で囲まれていない場合、変数は展開されます。詳細については、 bashマニュアル を参照してください。
_command << Word ... Word
_の出力を別のコマンドに直接パイプしたい場合は、_<< Word
_と同じ行にパイプを配置する必要があります。終了するWordの後や、行フォロー。例えば:
_ command << Word | command2 | command3...
Text
Word
_
_<<<
_:ここの文字列。ここのドキュメントに似ていますが、1行を対象としています。これらは、Unixポートまたはrc(元の場所)、zsh、ksh、yash、bashの一部の実装にのみ存在します。
_command <<< Word
_
Word
として指定されたものはすべて展開され、その値は入力としてcommand
に渡されます。これは、変数の内容をコマンドへの入力として渡すためによく使用されます。例えば:
_ $ foo="bar"
$ sed 's/a/A/' <<< "$foo"
bAr
# as a short-cut for the standard:
$ printf '%s\n' "$foo" | sed 's/a/A/'
bAr
# or
sed 's/a/A/' << EOF
$foo
EOF
_
他のいくつかの演算子(_>&-
_、_x>&y
_ _x<&y
_)を使用して、ファイル記述子をクローズまたは複製できます。それらの詳細については、シェルのマニュアルの関連セクションを参照してください( ここでは たとえばbashの場合)。
これは、Bourneのようなシェルの最も一般的な演算子のみをカバーしています。一部のシェルには、独自のリダイレクト演算子がいくつかあります。
Ksh、bash、およびzshには、<(…)
、>(…)
および=(…)
(後者はzsh
にのみ存在する)構文もあります。これらはリダイレクトではありませんが、 プロセス置換 です。
I/Oリダイレクト(<
および>
)について学んだばかりのUnix初心者は、しばしば次のようなことを試します
コマンド … 入力ファイル > the_same_file
または
コマンド …< ファイル > the_same_file
または、ほぼ同等に、
ネコ ファイル | コマンド …> the_same_file
(grep
、sed
、cut
、sort
、spell
は、このような構成で人々が使用したくなるコマンドの例です。)これらのシナリオの結果、ファイルが空になることにユーザーは驚いています。
他の回答で言及されていないように見えるニュアンスは、 bash(1) のRedirectionセクションの最初の文に潜んでいます:
コマンドが実行される前に、シェルによって解釈される特別な表記法を使用して、その入力と出力を redirected することができます。
最初の5つの単語は、太字、斜体、下線付き、拡大、点滅、赤く着色され、 アイコン。コマンドが実行される前に、シェルが要求されたリダイレクトを実行することを強調します。そしてまた覚えて
出力のリダイレクトにより、ファイル…が書き込み用に開かれます…。ファイルが存在しない場合は作成されます。存在する場合は、サイズがゼロに切り捨てられます。
したがって、この例では:
sort roster > roster
シェルは、roster
プログラムが実行を開始する前に、sort
ファイルを書き込み用に開き、切り捨てます(つまり、その内容をすべて破棄します)。当然、データを回復するためにできることは何もありません。
ナイーブにそれを期待するかもしれません
tr "[:upper:]" "[:lower:]" < poem > poem
良いかもしれません。シェルは左から右へのリダイレクトを処理するため、読み取り(poem
の標準入力の場合)のためにtr
を開いてから、書き込み(標準出力の場合)のために開きます。しかし、それは役に立ちません。この一連の操作により2つのファイルハンドルが生成されますが、どちらも同じファイルを指します。シェルが読み取りのためにファイルを開いたとき、コンテンツはまだそこにありますが、プログラムが実行される前にファイルが破壊されます。
ソリューションは次のとおりです。
実行しているプログラムに、出力先を指定する独自の内部機能があるかどうかを確認します。多くの場合、これは-o
(または--output=
)トークンで示されます。特に、
sort roster -o roster
にほぼ等しい
sort roster > roster
ただし、最初のケースでは、sort
プログラムが出力ファイルを開きます。そして、 after がすべての入力ファイルを読み取るまで、出力ファイルを開かないように賢くなっています。
同様に、少なくとも一部のバージョンのsed
には-i
(編集 私n place)出力を入力ファイルに書き戻すために使用できるオプション(ここでも、 after すべての入力が読み込まれた)。 ed
/ex
、emacs
、pico
、vi
/vim
などのエディターを使用すると、ユーザーはテキストファイルを編集し、編集したテキストを元のファイルに保存できます。 ed
は(少なくとも)非対話的に使用できることに注意してください。
vi
には関連機能があります。 :%!command
と入力した場合Enter、編集バッファーの内容をcommand
に書き込み、出力を読み取り、バッファーに挿入します(元の内容を置き換えます)。シンプルだが効果的:
コマンド … 入力ファイル > temp_file && mv temp_file入力ファイル
これには、input_file
がリンクの場合、(おそらく)別のファイルに置き換えられるという欠点があります。また、新しいファイルはデフォルトの保護であなたが所有します。特に、元のinput_file
がそうでなかったとしても、ファイルが最終的に誰でも読み取り可能になるというリスクがあります。
バリエーション:
command … input_file > temp_file && cp temp_fileinput_file && rm temp_file
temp_file
は世界中で読み取り可能です。さらに良い:cp input_filetemp_file && command … temp_file > input_file && rm temp_file
cp
で-a
や-p
などのオプションを使用して、属性を保持するように指示する必要がある場合があります。)command … input_file > temp_file &&
cp --attributes-only --preserve=all input_filetemp_file &&
mv temp_fileinput_file
このブログ (ファイルの「インプレース」編集)の提案と説明
{rm 入力ファイル && コマンド …> 入力ファイル; } < 入力ファイル
これには、command
が標準入力を処理できる必要があります(ただし、ほとんどすべてのフィルターで可能です)。ブログ自体はこれを危険なクラッジと呼んでおり、その使用を推奨していません。また、これにより、ユーザーが所有し、デフォルトの権限が付与された新しいファイル(何にもリンクされていない)も作成されます。
Moreutilsパッケージには、sponge
というコマンドがあります。
コマンド … 入力ファイル |スポンジ the_same_file
詳細は this answer を参照してください。
これは私にとってまったくの驚きでした: syntaxerrorによると :
[これらのソリューションのほとんど]は、読み取り専用ファイルシステムでは失敗します。「読み取り専用」とは、
$HOME
/は書き込み可能ですが、/tmp
は読み取り専用(デフォルト)になります。たとえば、Ubuntuを使用していて、回復コンソールを起動した場合、これは一般的なケースです。また、ヒアドキュメント演算子<<<
も一時ファイルをそこに書き込むため、/tmp
をread/writeにする必要があるため、そこでも機能しません。
(cf。 この質問 にはstrace
’dの出力が含まれます)
その場合、以下が機能する可能性があります。
sort
、またはtr
without the -d
または-s
オプション)、お試しいただけますコマンド … 入力ファイル | dd of =the_same_file conv = notrunc上記の説明を含む詳細、およびコマンドが同じ量を生成することが保証されている場合に機能する代替手段については、 この答え および この答え を参照してください入力があるときの出力データの数またはless (たとえば、
grep
、またはcut
)。これらの回答には、空き容量が必要ない(または必要な容量が少ない)という利点があります。上記のcommand … input_file > temp_file && …
形式の回答では、入力(古い)ファイル全体と出力(新しい)ファイル全体を同時に保持できる十分な空き領域がシステムに必要であることは明らかです。これは、他のほとんどのソリューション(sed -i
やsponge
など)でも明らかにそうではありません。例外:sort
は、出力を書き込む前にすべての入力を読み取る必要があるため、sort … | dd …
はおそらく多くの空き領域を必要とし、一時ファイル内のすべてのデータではないにしても、ほとんどのバッファリングを行います。コマンド … 入力ファイル 1 <> the_same_file上記の
dd
の回答と同じです。 n<>file
構文は、指定されたファイルをファイル記述子n
に対して、切り捨てることなく、入力と出力の両方で開きます –ソートn<
とn>
の組み合わせ。注:一部のプログラム(cat
やgrep
など)は、入力と出力が同じファイルであることを検出できるため、このシナリオでは実行を拒否する場合があります。上記のディスカッションについては this answer を参照してください。また、コマンドが入力と同じ量の出力データを生成することが保証されている場合にこの回答を機能させるスクリプト以下。これはU&Lで人気のトピックです。次の質問で取り上げます。
iconv
で入力ファイルを変換された出力に置き換えるにはどうすればよいですか?shuf file > file
が空のファイルを残す理由sort
コマンドで空のファイルが返されるのはなぜですか?tr
stdoutをファイルにリダイレクト…そして、それはスーパーユーザーやAsk Ubuntuをカウントしていません。上記の質問に対する回答の多くの情報をこの回答に組み込みましたが、すべてではありません。 (詳細については、上記の質問とその回答をご覧ください。)
追伸私は、上記で引用したブログとnoの提携を結んでいます。
;
、&
、(
、)
に関するその他の観測Terdonの回答の一部のコマンドはnullである可能性があることに注意してください。たとえば、あなたは言うことができます
command1 ;
(command2
なし)。これは
command1
(つまり、フォアグラウンドでcommand1
を実行し、それが完了するのを待ちます。同等に、
command1 &
(command2
なし)はcommand1
をバックグラウンドで起動し、すぐに別のシェルプロンプトを発行します。
対照的に、command1 &&
、command1 ||
、command1 |
は意味がありません。これらの1つを入力すると、シェルは(おそらく)コマンドが別の行に続くと想定します。通常は>
に設定されているセカンダリ(継続)シェルプロンプトが表示され、読み続けます。シェルスクリプトでは、次の行を読み取り、すでに読み取ったものに追加します。 (注意:これはあなたが起こしたいことではないかもしれません。)
注:一部のシェルの一部のバージョンでは、このような不完全なコマンドをエラーとして扱う場合があります。このような場合(または、実際には、コマンドが長いanyの場合)、バックスラッシュ(\
)を行の最後に置いて、シェルに別の行でコマンドを読み続けます:
command1 && \
command2
または
find starting-directory -mindepth 3 -maxdepth 5 -iname "*.some_extension" -type f \
-newer some_existing_file -user fred -readable -print
Terdonが言うように、(
および)
を使用してコマンドをグループ化できます。それらがその議論に「実際には関連していない」という陳述は議論の余地があります。 terdonの回答に含まれるコマンドの一部は、コマンドgroupsの場合があります。例えば、
( command1 ; command2 ) && ( command3; command4 )
これを行います:
command1
を実行し、終了するまで待ちます。command2
を実行して、コマンドが完了するまで待ちます。次に、command2
が成功した場合、
command3
を実行し、終了するまで待ちます。command4
を実行して、コマンドが完了するまで待ちます。command2
が失敗した場合は、コマンドラインの処理を停止します。
括弧の外では、|
は非常に強く結合するため、
command1 | command2 || command3
に相当
( command1 | command2 ) || command3
および&&
および||
は;
よりも緊密にバインドするため、
command1 && command2 ; command3
に相当
( command1 && command2 ) ; command3
つまり、command3
は、command1
やcommand2
の終了ステータスに関係なく実行されます。