私は偶然、bash では を使用せずにコマンドを変数に割り当てることができることを知りましたalias
。
g=date
$g
Mon Jun 27 13:00:40 MYT 2016
それはうまくいきます。別の例を示します。
jj="ping yahoo.com"
$jj
PING yahoo.com (98.138.253.109) 56(84) bytes of data.
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=1 ttl=41 time=347 ms
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=2 ttl=41 time=345 ms
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=3 ttl=41 time=345 ms
私はこのバージョンのbashを使用していますbash --version GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
私は調べてみたスタックエクスチェンジそしてtldp 腹筋しかし、このようにできるとは思えませんでした。これはbashの新機能でしょうか、それとも見落とされているのでしょうか?これは考慮されていますか?コマンド置換?
答え1
対話型使用では、シェルは端末デバイスから入力行を読み取ります。行が入力されると、解析された分割してトークン(単語と演算子)。トークンまたは単語は、特定の順序で展開または解決されます。
注: 一般的に、Advanced Bash-Scripting Guide、オンライン チュートリアル、書籍、さらには Stack Exchange などの二次情報源よりも、プロジェクト ドキュメントや業界仕様などの標準的な情報源を参照するのが最適です。このような二次情報源は、より簡単な言葉で概念を紹介および説明するのに役立ちますが、通常は完全なものになることや公式ドキュメントに代わるものではありません。二次情報源の情報は古くなっている場合もあります。
この場合、シンプルコマンドを解析するためのPOSIX仕様と述べています
- 変数割り当てまたはリダイレクトではない単語は展開されます。展開後にフィールドが残っている場合、最初のフィールドはコマンド名と見なされ、残りのフィールドはコマンドの引数と見なされます。
のBash マニュアルの「シンプルなコマンド展開」セクションまた、
- 変数の割り当てやリダイレクトではない単語は展開されます (シェルの展開を参照)。展開後に単語が残っている場合は、最初の単語がコマンドの名前とみなされ、残りの単語が引数になります。
答え2
これはコマンド置換ではなく、変数置換。変数にコマンドを割り当てるのではなく、文字列を割り当てます。コマンドは割り当て時ではなく、変数を使用するときに実行されます。
g=date
は、文字列をdate
変数 に格納しますg
。その後 を実行すると、 の値が最初の引数としてコマンドに渡されるため、 の値、つまり(改行が続く)echo "$g"
が出力されます。 を実行すると、文字列がコマンドの最初の位置に配置され、それがコマンド名になります。g
date
g
echo
"$g"
date
では$jj
、2番目の要素が作用します。変数の展開は引用符の外側にあるため、「split+glob演算子」が値に適用されます。この場合、これは の値がjj
スペースで区切られた 2 つの単語に分割されることを意味します。したがって、単語はping
コマンドの位置に配置され、単語はyahoo.com
最初の引数になります。
答え3
これは予想される動作であり、長年機能してきました。スクリプトでコマンドを構築するのに便利です。
たとえば、入力をパイプラインに送信する前に圧縮解除する必要がある場合と、そうでない場合があるとします (その後、出力を圧縮する必要があります)。次のように使用しますbash
。
if (( use_compression == 1 )); then
infilter='gzip -d -c'
outfilter='gzip -c'
else
infilter='cat'
outfilter='cat'
fi
$infilter "$indatafile" | somepipeline | $outfilter >"$outdatafile"
$(...)
これはコマンド置換ですか? いいえ。「コマンド置換」とは、具体的には、バックティックバリアントをその出力の内容に置き換えることを指します。
これは代わりにパラメータ拡張つまり、パラメータをその値に置き換えるだけです。これはコマンドが実際に実行される前に行われるため、機能します。
つまり、次のようなものがコマンド ラインでも機能します。
$ decompress='gzip -d -c'
$ ${decompress/g/gun/} filename >unzippedfilename
(gunzip
ではなく実行されるgzip
)
編集:エイリアスについて。
マニュアルbash
にはこう書かれています:
ほとんどすべての目的において、エイリアスはシェル関数に置き換えられます。
...私も同意します。
エイリアスは次のような短いものに適しています
alias ls="ls -F"
(これは私自身のシェル セッションで使用している唯一のエイリアスです)
おそらく、コマンド ラインでコマンドを「エイリアス」するためにパラメータ展開を使用するのは望ましくないでしょう。他の理由がない限り、入力するのが面倒だからです。パラメータ展開では、パイプライン処理などの少し複雑なタスクを実行することもできません。
定期的に実行する中程度に複雑な操作がある場合は、代わりにシェル関数を使用してください。
受け入れられた回答の例を挙げると、U&Lの質問(以下のコメント欄にリンクします):
alias my_File='ls -f | grep -v /'
このエイリアスは明らかに機能しますが、
my_File='ls -f | grep -v /'
$my_File
その後、コマンド ラインでコマンドとして使用しようとすると機能しません(理由は U&L スレッドで説明されています)。
シェル関数を使用すると、引数を渡すなどの操作も実行できます。
function my_File {
ls -l "$@" | fgrep -v '/'
}
$ my_File -iF symlink
84416642 lrwxr-xr-x 1 kk staff 4 Jun 27 09:03 symlink@ -> file
答え4
これは単にシェル変数を使用しているだけであり、この概念は何十年も前から存在し、そのように機能してきました (誇張ではありません)。
コマンドラインに変数を置くと、シェルはそれを置き換えてからコマンドを実行するので、変数が先頭にある場合は当然コマンドとして扱われます。