コマンド置換
コマンドの実行結果を、そのまま変数や別のコマンドの一部として使う仕組みがコマンド置換です。$(コマンド) と書くと、中のコマンドが先に実行され、その標準出力に置き換わります。例えば today=$(date +%F) とすれば、今日の日付を変数に取り込めます。古い書き方のバッククオート `...` も同じ意味ですが、入れ子にしづらいため、今は $(...) が推奨されます。
スクリプトを書いていると、「あるコマンドを実行した結果を、そのまま別の場所で値として使いたい」という場面が頻繁に出てきます。たとえば今日の日付をファイル名に入れたい、今いるディレクトリのパスを変数に取り込みたい、といった具合です。こうした「コマンドの実行結果を文字列として埋め込む」仕組みがコマンド置換です。これを使えると、固定の値を手で書く代わりに、その時々で変わる動的な値をスクリプトに自然に組み込めるようになり、自動化の幅が一気に広がります。
$(コマンド) の基本
コマンド置換は $(コマンド) という形で書きます。$( と ) で囲まれた中のコマンドが先に実行され、その標準出力(画面に出るはずだった文字列)が、そっくりその場所に置き換わります。たとえば today=$(date +%F) と書くと、まず date +%F が実行されて 2026-06-27 のような日付文字列が得られ、それが変数 today に代入されます。続けて echo "今日は $today です" とすれば「今日は 2026-06-27 です」と表示されます。date +%F の +%F は、日付を「年-月-日」の形式で出すための指定です。同じ要領で dir=$(pwd) とすれば現在地のパスを変数に取り込めますし、count=$(ls | wc -l) のように他のコマンドと組み合わせて、ファイル数を数えて変数に入れる、といった使い方もできます。
コマンド置換は変数への代入だけでなく、別のコマンドの引数の一部としても直接使えます。たとえば echo "カーネルは $(uname -r) です" のように文中に埋め込めますし、mkdir "backup_$(date +%Y%m%d)" とすれば「backup_20260627」のような日付入りのディレクトリ名を一発で作れます。「コマンドの出力をその場の文字列に変える」と捉えると、応用の見当が付きやすくなります。
古い書き方のバッククオートとの違い
コマンド置換には、古くから使われてきたバッククオート `コマンド` という書き方もあります。`date +%F` のように逆向きの引用符(バッククオート)で囲む形で、結果は $(date +%F) とまったく同じです。古い教材やスクリプトではこちらをよく見かけるので、読めるようにはしておきましょう。ただし新しく書くときは $(...) を使うのが推奨されています。理由のひとつが入れ子のしやすさです。$( ) は $(echo $(date +%F)) のように素直に重ねて書けますが、バッククオートは入れ子にしようとするとバックスラッシュでエスケープが必要になり、読みにくく間違いやすくなります。もうひとつ、バッククオートは画面上でシングルクオートと見分けづらく、誤読を招きやすいという問題もあります。これらの理由から、現在では $(...) に統一しておくのが無難です。
改行の扱いとクオートの注意
コマンド置換で気を付けたいのが出力の改行の扱いです。$( ) は、取り込んだ出力の末尾にある改行を取り除いてくれます。そのため date のように1行だけ出すコマンドなら、余計な改行が付かずきれいに値が入ります。一方、複数行を出すコマンドの結果を変数に入れた場合、その値をダブルクオートで囲まずに使うと、シェルが空白や改行で値を分割してしまい、行のまとまりが崩れることがあります。複数行の結果を1つの塊として扱いたいときは、echo "$result" のように必ずダブルクオートで囲むのが安全です。囲まずに echo $result と書くと、改行が空白に変換されて全部が1行に詰められてしまうので、出力の見た目が変わってしまいます。
もうひとつ知っておきたいのが、$( ) の中は「別のシェル(サブシェル)」として実行されるという点です。コマンド置換の内側で変数に代入したり cd でディレクトリを移動したりしても、その効果は $( ) の外側の本体には残りません。たとえば dir=$(cd /tmp; pwd) と書いても、本体のカレントディレクトリは /tmp には変わらず、あくまで dir という変数に /tmp という文字列が入るだけです。「中で起きたことは値だけが外に出てくる」と捉えると、この挙動に戸惑わずに済みます。また、まだ値の入っていない(存在しない)コマンドや空の出力を $( ) で受けると、変数が空文字になります。空のまま後続の処理に渡すと条件式が崩れたりファイル名が欠けたりするので、結果が空でないかを if [ -n "$result" ] のように確かめてから使うと、より堅牢なスクリプトになります。
実務での使いどころ
コマンド置換は、実務のスクリプトでほぼ必ず登場する基本テクニックです。代表的なのは、ログファイルやバックアップに日時を埋め込む用途で、logfile="app_$(date +%Y%m%d_%H%M%S).log" のように書けば、実行のたびに重ならないファイル名を自動で作れます。ほかにも、host=$(hostname) でホスト名を取り込んで通知メッセージに入れたり、pid=$(pgrep -f myapp) で特定プロセスの番号を取得して後続の処理に渡したり、といった形で活躍します。「この値はその時々で変わるから手では書けない」という場面に出会ったら、それを出力してくれるコマンドを $( ) で包んで埋め込めないかを考える——これがコマンド置換を使いこなす発想の出発点です。コマンド置換は for ループのリスト部分とも好相性で、for f in $(ls *.log); のように書けば、コマンドが出力した一覧をそのまま繰り返しの対象にできます(ただしファイル名に空白が含まれる場合は for f in *.log; のようにワイルドカードを直接使うほうが安全です)。なお、足し算などの計算結果を埋め込みたい場合は、コマンド置換ではなく算術展開 $(( )) を使います。today=$(date +%F) のようにコマンドの出力を取り込むのが $( )、sum=$(( a + b )) のように式を計算するのが $(( )) と、丸カッコの数で役割が分かれている点も合わせて覚えておくと混同しません。