私はBashが次の行をどのように扱うかを理解しようとしています:
$(< "$FILE")
Bashのmanページによると、これは次と同等です。
$(cat "$FILE")
この2行目の推論の行を追うことができます。 Bashは$FILE
で変数展開を実行し、コマンド置換を入力し、$FILE
の値をcat
に渡し、catは$FILE
の内容を標準出力に出力し、コマンド置換は次のように終了します。行全体を内部のコマンドの結果である標準出力に置き換えると、Bashは単純なコマンドのようにそれを実行しようとします。
ただし、上記の最初の行については、Bashが$FILE
で変数置換を実行し、Bashが標準入力で読み取るために$FILE
を開くどういうわけか標準入力が標準出力にコピーされます、コマンド置換が終了し、Bashは結果の標準出力を実行しようとします。
誰かが$FILE
の内容がstdinからstdoutにどのように変わるか説明してくれませんか?
$(<file)
(`<file`
でも機能)は、zsh
およびbash
によってコピーされたKornシェルの特殊な演算子です。コマンド置換によく似ていますが、実際はそうではありません。
POSIXシェルでは、簡単なコマンドは次のとおりです。
< file var1=value1 > file2 cmd 2> file3 args 3> file4
すべての部分はオプションであり、リダイレクトのみ、コマンドのみ、割り当てのみ、または組み合わせが可能です。
リダイレクトはあるがコマンドがない場合、リダイレクトは実行されます(つまり、> file
が開き、file
が切り捨てられます)が、何も起こりません。そう
< file
file
を読み取り用に開きますが、コマンドがないため何も起こりません。したがって、file
は閉じられ、それだけです。 $(< file)
が単純なコマンド置換の場合、何も展開されません。
POSIX仕様 、$(script)
では、script
がリダイレクトのみで構成されている場合、は不特定の結果を生成します。これは、Korn Shellの特別な動作を可能にするためです。
Ksh(ここではksh93u+
でテスト)で、スクリプトが1つだけで構成されている場合単純なコマンド(コメントは前後に許可されます)のみで構成されますリダイレクト(コマンドなし、割り当てなし)の場合、および最初のリダイレクトがstdin(fd 0)入力のみ(<
、<<
または<<<
)リダイレクトの場合、次のようになります。
$(< file)
$(0< file)
$(<&3)
(実際には同じ演算子なので、実際には$(0>&3)
も)$(< file > foo 2> $(whatever))
だがしかし:
$(> foo < file)
$(0<> file)
$(< file; sleep 1)
$(< file; < file2)
その後
<&3
のようなものを使用する場合はファイル記述子から読み取ることができるもの)の内容から末尾の改行文字を除いたものに展開されます。$(cat < file)
を使用しているかのように
cat
ではなく、シェルによって内部的に行われます$(<${file=foo.txt})
または$(<file$((++n)))
のように)zsh
でも同じですが、ファイルの入力リダイレクトが1つしかない場合にのみ特別な動作がトリガーされます(<file
または0< file
、<&3
、<<<here
、< a < b
...)
ただし、他のシェルをエミュレートする場合を除いて、次の場所にあります。
< file
<&3
<<< here...
つまり、コマンド置換以外のコマンドなしの入力リダイレクトのみがある場合、zsh
は$READNULLCMD
(デフォルトではページャー)を実行し、入力リダイレクトと出力リダイレクトの両方がある場合は、$NULLCMD
(cat
byしたがって、$(<&3)
がその特殊な演算子として認識されない場合でも、ページャーを呼び出してそれを実行することで、ksh
のように機能します(そのページャーは、cat
のように動作します。stdoutがパイプ)。
ただし、ksh
の$(< a < b)
はa
のコンテンツに展開されますが、zsh
ではa
およびb
(またはb
multios
オプションが無効になっている場合)、$(< a > b)
はa
をb
にコピーし、何も展開しない、などです。
bash
にも同様の演算子がありますが、いくつかの違いがあります。
コメントは前では許可されますが、後では許可されません:
echo "$(
# getting the content of file
< file)"
動作しますが:
echo "$(< file
# getting the content of file
)"
何にも拡張されません。
zsh
と同様に、$READNULLCMD
へのフォールバックはありませんが、1つのファイルstdinリダイレクトのみなので、$(<&3)
、$(< a < b)
はリダイレクトを実行しますが、何も展開しません。
bash
はcat
を呼び出さない一方で、パイプを介してファイルのコンテンツをフィードするプロセスをフォークし、他のシェルよりも最適化がはるかに少なくなります。これは、実際には$(cat < file)
のようなもので、cat
は組み込みcat
になります。$(<${file=foo.txt})
では、その$file
割り当ては後で失われます)。bash
では、IFS= read -rd '' var < file
(zsh
でも機能)は、textファイルの内容を読み込むより効果的な方法です変数。また、末尾の改行文字を保持するという利点もあります。 zsh
の$mapfile[file]
も参照してください(zsh/mapfile
モジュール内で、通常のファイルのみ)。これもバイナリファイルで機能します。
ksh
のpdkshベースのバリアントには、ksh93と比較していくつかのバリエーションがあることに注意してください。興味深いことに、mksh
(これらのpdksh派生シェルの1つ)では、
var=$(<<'EOF'
That's multi-line
test with *all* sorts of "special"
characters
EOF
)
ヒアドキュメントのコンテンツ(末尾の文字なし)が一時ファイルやパイプを使用せずに展開されるという点で最適化されています。そうでない場合はヒアドキュメントの場合と同様に、効果的な複数行の引用構文になります。
ksh
、zsh
、およびbash
のすべてのバージョンに移植できるようにするために、コメントを避け、内部で行われた変数への変更が保持される場合と保持されない場合があることを念頭に置いて、$(<file)
のみに制限することをお勧めします。 。
bash
は内部で行うため、$(cat < filename)
を実行する場合と同様に、ファイル名を拡張してファイルを標準出力に出力します。これはbashの機能です。おそらく、bash
ソースコードを調べて、その機能を正確に知る必要があります。
ここで、この機能を処理する関数(bash
ソースコード、ファイル_builtins/evalstring.c
_から):
_/* Handle a $( < file ) command substitution. This expands the filename,
returning errors as appropriate, then just cats the file to the standard
output. */
static int
cat_file (r)
REDIRECT *r;
{
char *fn;
int fd, rval;
if (r->instruction != r_input_direction)
return -1;
/* Get the filename. */
if (posixly_correct && !interactive_Shell)
disallow_filename_globbing++;
fn = redirection_expand (r->redirectee.filename);
if (posixly_correct && !interactive_Shell)
disallow_filename_globbing--;
if (fn == 0)
{
redirection_error (r, AMBIGUOUS_REDIRECT);
return -1;
}
fd = open(fn, O_RDONLY);
if (fd < 0)
{
file_error (fn);
free (fn);
return -1;
}
rval = zcatfd (fd, 1, fn);
free (fn);
close (fd);
return (rval);
}
_
$(<filename)
は$(cat filename)
とまったく同じではないことに注意してください。ファイル名がダッシュ_-
_で始まる場合、後者は失敗します。
$(<filename)
は元々ksh
からのものであり、_Bash-2.02
_からbash
に追加されました。