
さまざまなコマンドをさまざまなシンボルで接続するチュートリアルをオンラインでよく見かけます。例:
command1 | command2
command1 & command2
command1 || command2
command1 && command2
他には、コマンドをファイルに接続しているようです:
command1 > file1
command1 >> file1
これらは何でしょう? 何と呼ばれていますか? 何をするのですか? 他にもあるのですか?
答え1
これらはシェル演算子と呼ばれ、他にもたくさんあります。2つの主要なクラスの中で最も一般的なものについて簡単に説明します。制御演算子そしてリダイレクト演算子、およびそれらが bash シェルに対してどのように機能するかについて説明します。
A. 制御演算子
シェル コマンド言語では、制御機能を実行するトークン。
次のいずれかのシンボルです。
& && ( ) ; ;; <newline> | ||
そして|&
bashで。
A!
はない制御演算子ではなく予約語内部では論理否定演算子になります算術式およびテスト構造内でも使用できます (ただし、スペース区切り文字は必要です)。
A.1 リスト終端子
;
: 最初のコマンドの結果に関係なく、別のコマンドが終了した後に次のコマンドを実行します。command1 ; command2
最初はcommand1
フォアグラウンドで実行され、終了すると がcommand2
実行されます。
文字列リテラル内または特定のキーワードの後にない改行はない;
セミコロン演算子と同等です。区切られた単純なコマンドのリストは、リスト- シェルのパーサーは、実行する前に、区切られた単純なコマンドに続く単純なコマンドを引き続き読み込む必要があります;
が、改行はコマンド リスト全体、またはリストのリストを区切ることができます。違いは微妙ですが複雑です。シェルには改行に続くデータの読み込みに関する命令が事前にないため、改行は、シェルが既に読み込んだ単純なコマンドの評価を開始できるポイントを示しますが、セミコロンは;
そうしません。
&
: これにより、コマンドがバックグラウンドで実行され、同じシェルで作業を継続できるようになります。command1 & command2
ここで、command1
はバックグラウンドで起動され、の終了command2
を待たずにすぐにフォアグラウンドで実行を開始しますcommand1
。
後の改行command1
はオプションです。
A.2 論理演算子
&&
: AND リストを作成するために使用され、別のコマンドが正常に終了した場合にのみ 1 つのコマンドを実行できます。command1 && command2
ここでは、終了command2
後に実行され、command1
のみ成功した場合command1
(終了コードが 0 の場合)。両方のコマンドはフォアグラウンドで実行されます。
このコマンドは次のようにも書けます
if command1
then command2
else false
fi
if command1; then command2; fi
または、戻りステータスが無視される場合も同様です。
||
: OR リストを作成するために使用され、別のコマンドが正常に終了しなかった場合にのみ 1 つのコマンドを実行できます。command1 || command2
ここでは、失敗したcommand2
場合(0 以外の終了ステータスを返した場合)のみ実行されますcommand1
。両方のコマンドはフォアグラウンドで実行されます。
このコマンドは次のようにも書けます
if command1
then true
else command2
fi
またはもっと短く言うとif ! command1; then command2; fi
。
&&
と は||
左結合であることに注意してください。シェルの論理演算子 &&、|| の優先順位詳細については。
!
: これは「not」演算子として機能する予約語です (ただし区切り文字が必要です)。コマンドの戻りステータスを否定するために使用されます。コマンドが 0 以外のステータスを返す場合は 0 を返し、ステータス 0 を返す場合は 1 を返します。ユーティリティの論理 NOT でもありますtest
。! command1 [ ! a = a ]
算術式内の真の NOT 演算子:
$ echo $((!0)) $((!23))
1 0
A.3 パイプ演算子
|
: パイプ演算子は、あるコマンドの出力を別のコマンドの入力として渡します。パイプ演算子から構築されたコマンドは、パイプライン。command1 | command2
によって印刷される出力はすべて
command1
への入力として渡されますcommand2
。|&
: これは bash および zsh の省略形です2>&1 |
。1 つのコマンドの標準出力と標準エラーの両方を別のコマンドの入力として渡します。command1 |& command2
A.4 その他のリスト句読点
;;
単に終了を示すために使用されるケースステートメントKsh、bash、zsh では、;&
次のケースにフォールスルーすることもサポートされており、;;&
(ATT ksh ではサポートされていませんが) 後続のケースをテストすることもできます。
(
そして)
慣れているグループコマンドサブシェルで起動します。{
また、}
グループコマンドも実行しますが、サブシェルでは起動しません。この答えシェル構文におけるさまざまな種類の括弧、角括弧、中括弧の説明。
B. リダイレクト演算子
シェル コマンド言語では、リダイレクト機能を実行するトークンです。次のいずれかのシンボルです。
< > >| << >> <& >& <<- <>
これらを使用すると、コマンドの入力と出力を制御できます。これらは、単純なコマンド内のどこにでも表示できます。また、コマンドの後に続くこともできます。リダイレクトは、表示される順序で、左から右に処理されます。
<
: コマンドに入力します。command < file.txt
上記はcommand
の内容に対して実行されますfile.txt
。
<>
: 上記と同じですが、ファイルは読み取り+書き込みモードの代わりに読み取り専用:command <> file.txt
ファイルが存在しない場合は作成されます。
この演算子は、コマンドが通常読むただし、stdinからはそれはいくつかの特定の状況で役に立つ可能性がある。
>
: コマンドの出力をファイルに送信します。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
、そこにすでにあるものの後に追加されます。 存在しない場合は作成されます。
>&
: (POSIX仕様による) で囲まれた場合数字(1>&2
)または-
右側(1>&-
)はリダイレクトのみを行います1つファイル記述子を削除するか、閉じます (>&-
)。
の後>&
にファイル記述子番号を続けると、ファイル記述子をリダイレクトする移植可能な方法となり、>&-
ファイル記述子を閉じる移植可能な方法となります。
このリダイレクトの右側がファイルである場合は、次のエントリを読んでください。
>&
、、&>
および>>&
:&>>
(上記も参照) 標準エラーと標準出力の両方をリダイレクトし、それぞれ置換または追加します。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
プロセス置換。
答え2
'>' に関する警告
<
I/Oリダイレクト(および)について学んだばかりのUnix初心者は、>
次のようなことをよく試みます。
指示…入力ファイル>同じファイル
または
指示…<ファイル >同じファイル
あるいは、ほぼ同等に、
猫ファイル|指示… >同じファイル
( grep
、、、、およびは、このような構造でユーザーが使用したくなるコマンドの例です。) ユーザーは、これらのシナリオでファイルsed
が空になることに驚きます。cut
sort
spell
他の回答では触れられていないニュアンスが、この質問の最初の文に潜んでいる。リダイレクションセクションバッシュ(1):
コマンドが実行される前に、その入力と出力はリダイレクト シェルによって解釈される特殊な表記法を使用します。
最初の5つの単語は、太字、斜体、下線、拡大、点滅、赤色、アイコンでマークされ、シェルが要求されたリダイレクトを実行していることを強調する 必要があります。コマンドが実行される前にそして覚えておいてください
出力をリダイレクトすると、ファイル … が書き込み用に開かれます …。ファイルが存在しない場合は作成され、存在する場合はサイズがゼロに切り捨てられます。
したがって、この例では次のようになります。
sort roster > roster
シェルは、プログラムの実行を開始する
roster
前に、ファイルを書き込み用に開き、ファイルを切り捨てます (つまり、その内容をすべて破棄します)sort
。当然、データを回復することはできません。素朴に期待する人もいるかもしれない
tr "[:upper:]" "[:lower:]" < poem > poem
の方が良いかもしれません。シェルはリダイレクトを左から右に処理するため、書き込み用
poem
(標準出力用) の前に読み取り用tr
(の標準入力用) で開きます。しかし、これは役に立ちません。この一連の操作によって 2 つのファイル ハンドルが生成されますが、どちらも同じファイルを指しています。シェルが読み取り用にファイルを開くと、内容はまだそこにありますが、プログラムが実行される前に上書きされてしまいます。
それで、どうすればいいのでしょうか?
ソリューションには以下が含まれます:
実行中のプログラムに、出力先を指定する独自の内部機能があるかどうかを確認します。これは、多くの場合、
-o
(または--output=
)トークンで示されます。特に、sort -o roster roster
は、ほぼ
sort roster > roster
ただし、最初のケースでは、
sort
プログラムは出力ファイルを開きます。そして、出力ファイルが開かれるまでは、後すべての入力ファイルを読み取りました。同様に、少なくともいくつかのバージョンのに
sed
は-i
(編集私n桁のオプションを使用して、出力を入力ファイルに書き戻すことができます(繰り返しますが、後ed
/ex
、、、および/などemacs
のエディタを使用すると、 ユーザーはテキストファイルを編集し、編集したテキストを元のファイルに保存できます。(少なくとも) は非対話的に使用できることに注意してください。pico
vi
vim
ed
vi
には関連する機能があります。 と入力すると、編集バッファの内容が:%!command
Entercommand
出力を読み取り、それをバッファに挿入します(元の内容を置き換えます)。
シンプルだが効果的:
指示…入力ファイル>一時ファイル && 動画一時ファイル 入力ファイル
これには欠点があり、
input_file
リンクの場合、別のファイルに置き換えられる可能性が高いです。また、新しいファイルはデフォルトの保護付きで、あなたが所有することになります。特に、元のファイルがリンクであっても、そのファイルが最終的に誰でも読める状態になってしまうリスクがあります。input_file
そうではなかった。バリエーション:
command … input_file > temp_file && cp temp_file input_file && rm temp_file
それでも(潜在的に)temp_file
世界中で読み取り可能。さらに良いのは:cp input_file temp_file && command … temp_file > input_file && rm temp_file
これらは、ファイルのリンク ステータス、所有者、およびモード (保護) を保持しますが、I/O が 2 倍になる可能性があります。(属性を保持するように指示するには、-a
または-p
on などのオプションを使用する必要がある場合がありますcp
。)command … input_file > temp_file &&
cp --attributes-only --preserve=all input_file temp_file &&
mv temp_file input_file
(読みやすくするために別の行に分割されています) これにより、ファイルのモード (および、root の場合は所有者) が保持されますが、ファイルの所有者は (root でない場合は) あなたになり、新しい別のファイルになります。
このブログ (ファイルの「インプレース」編集)を提案し、説明する
{ rm入力ファイル && 指示… >入力ファイル; } <入力ファイル
これには、
command
標準入力を処理できる必要があります (ただし、ほぼすべてのフィルターは処理できます)。ブログ自体はこれを危険なクルージュと呼び、使用を推奨していません。また、これにより、新しい別のファイル (何にもリンクされていない) が作成され、所有者はあなたで、デフォルトの権限が付与されます。moreutils パッケージには、次のコマンドがあります
sponge
:指示…入力ファイル| スポンジ同じファイル
見るこの答え詳細については。
私にとってまったく驚きだったことが一つあります。 構文エラーは言う:
[これらのソリューションのほとんどは]読み取り専用ファイルシステムでは機能しません。「読み取り専用」とは、
$HOME
意思書き込み/tmp
可能だが、読み取り専用(デフォルト)。例えば、Ubuntuを使用していて、回復コンソールを起動した場合、これはよくあるケースです。また、ヒアドキュメント演算子も<<<
動作しません。/tmp
読み書き そこにも一時ファイルが書き込まれるためです。
(cf.この質問'd出力を含むstrace
)
その場合は、次の方法が効果的かもしれません:
- 上級ユーザーのみ:
コマンドが入力と同じ量の出力データを生成することが保証されている場合(例:
sort
、またはtr
それなしまたはオプション)を試すことができ-d
ます-s
指示…入力ファイル| dd の=同じファイルconv=notrunc
見るこの答え そしてこの答え上記の説明や、コマンドが入力と同じ量の出力データを生成することが保証されている場合に機能する代替手段など、詳細については、以下(例:grep
、またはcut
)。これらの回答には、空き領域を必要としない (またはほとんど必要としない) という利点があります。 フォームの上の回答では、 システムが入力 (古い) ファイルと出力 (新しい) ファイル全体を同時に保持できるだけの十分な空き領域が必要であることは明らかです。これは、他のほとんどのソリューション (例:および) にも必ずしも当てはまりません。 例外:は、出力を書き込む前にすべての入力を読み取る必要があり、そのデータのすべてではないにしても大部分を一時ファイルにバッファリングするため、大量の空き領域が必要になる可能性があります。command … input_file > temp_file && …
sed -i
sponge
sort … | dd …
sort
- 上級ユーザーのみ:
指示…入力ファイル1<>同じファイル
上記の答えと同等かもしれませんdd
。構文はファイル記述子で指定されたファイルを開きますn<> file
n
入力と出力の両方 を切り捨てずに、とを組み合わせたようなものになります。注: 一部のプログラム (例:および) は、入力と出力が同じファイルであることを検出できるため、このシナリオでは実行を拒否する場合があります。n<
n>
cat
grep
この答え 上記の議論と、コマンドが入力と同じ量の出力データを生成することが保証されている場合にこの回答を機能させるスクリプトについては、以下警告
: Peter のスクリプトはテストしていないので、保証はできません。
それで、質問は何でしたか?
これは U&L で人気のトピックであり、次の質問で取り上げられています。
- ファイルをその場で変更する方法はありますか?
iconv
入力ファイルを変換された出力に置き換えるにはどうすればよいですか?- コマンドを実行
shuf file > file
すると空のファイルが残るのはなぜですか? - Linux で同じファイルを上書きせずに読み書きできますか?
- コマンドによって処理されたソースファイルと同じファイルにリダイレクトします
sort
このコマンドを実行すると空のファイルが生成されるのはなぜですか?tr
stdout をファイルにリダイレクトする- grep: 入力ファイル 'X' は出力ファイルでもある
- リダイレクト演算子はファイル記述子を並列に開きますか?
- リダイレクトはファイルを上書きせず、空のファイルを生成するだけです
…そして、Super User や Ask Ubuntu は含まれていません。上記の質問に対する回答の多くの情報をこの回答に取り入れていますが、すべてではありません。(つまり、詳細については、上記の質問とその回答を読んでください。)
追伸:私はいいえ上記で引用したブログとの提携。
答え3
;
、、&
および(
に関するさらなる観察)
terdonの回答にあるコマンドの一部はnullになる可能性があることに注意してください。たとえば、次のように言うことができます。
command1 ;
( はなし
command2
)。これは、command1
(つまり、
command1
フォアグラウンドで実行され、完了するまで待機するだけです。比較すると、command1 &
( なし
command2
) はバックグラウンドで起動しcommand1
、すぐに別のシェルプロンプトを発行します。対照的に、、、
command1 &&
およびcommand1 ||
はcommand1 |
意味をなしません。これらのいずれかを入力すると、シェルは (おそらく) コマンドが別の行に継続されていると想定します。通常は に設定されているセカンダリ (継続) シェル プロンプトを表示し>
、読み取りを続行します。シェル スクリプトでは、次の行を読み取り、既に読み取った行に追加します。(注意: これは、望んでいる動作ではない可能性があります。)注意:一部のシェルのバージョンでは、このような不完全なコマンドをエラーとして扱う場合があります。そのような場合(または実際には、どれでも長いコマンドがある場合など、
\
行末にバックスラッシュ ( ) を付けて、シェルに次の行のコマンドの読み取りを続行するように指示することができます。command1 && \ command2
または
find starting-directory -mindepth 3 -maxdepth 5 -iname "*.some_extension" -type f \ -newer some_existing_file -user fred -readable -print
terdonが言うように、
(
コマンド)
をグループ化するために使用できます。それらが「その議論にはあまり関係がない」という発言は議論の余地があります。terdonの回答にあるコマンドのいくつかは、コマンドである可能性があります。グループ。 例えば、( 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