Bashの特殊な変数$_を使って直前に実行されたコマンドの引数を取得する

2023-04-16Bash

はじめに

先日、他の方が作成されたスクリプトを拝見していたときに見つけた特殊変数 $_ があまり見慣れないものだったので、調べてみました。

検証環境

$ uname -moi
aarch64 aarch64 GNU/Linux

$ head -n 2 /etc/os-release
PRETTY_NAME="Ubuntu Kinetic Kudu (development branch)"
NAME="Ubuntu"

$ bash -version | head -n 1
GNU bash, バージョン 5.1.16(1)-release (aarch64-unknown-linux-gnu)

スクリプトで使われていた $_ 特殊変数について

Bash では 全ての引数を表す $@引数の数を表す $#  、 実行中のプロセス ID を表す $$ など、いくつか組み込み機能として提供されている変数があります。

$_ はそういった変数のうちの 1 つになります。

では、 $_ はどのような変数なのでしょうか。

$_  変数は「直前に実行されたコマンドの最後の引数」を表す

$_  変数は「直前に実行されたコマンドの最後の引数」を表します。

早速具体的な例を見ていきましょう。

$_ 変数が利用されていたコードは以下のようなものになっていました。

$ mkdir hoge && cd "$_"

こちらの命令を実際に実行してみたいと思います。

実行前、実行後にカレントディレクトリを出力してみます。

$ pwd
/workdir

# hoge/ ディレクトリを作成し、 `$_` の指し示すディレクトリに移動
$ mkdir hoge && cd "$_"

$ pwd
/workdir/hoge

こちらのコードからわかるのは、 $_hoge を示しているということです。
値を出力してみましょう。

$ mkdir hoge

$ echo $_
hoge

確かに $_hoge という値を示しています。

$_ は、直前に実行されたコマンドの引数を表す変数であることがわかります

もう一つ実験してみます。
直前に実行されたコマンドの引数が複数だった場合はどのような挙動になるでしょう?

$ echo aa bb cc
aa bb cc

$ echo $_
cc

aa / bb / cc の 3 つの引数のうち、最後の引数 cc の値だけが格納されていることがわかりました。

$_ は、直前に実行されたコマンドの最後の引数を表す変数であることがわかります

ちょっとしたコマンドの連続であれば登場する変数を減らすことができる

$_ をうまく使えば、変数を上手にへらすことができます。

例えば以下のような操作を想定してみます。

  1. ディレクトリを作成
  2. 作成したディレクトリに移動
  3. git init して Git ワークスペースとして初期化

$_ 変数を使わない場合、以下のように記述することができます。

$ REPO_NAME=hello

$ mkdir $REPO_NAME

$ cd $REPO_NAME

$ git init
Initialized empty Git repository in /Users/genzouw/hello/.git/

$_ 変数を使うことで、以下のように記述することができます。

$ mkdir hello

$ cd $_

$ git init
Initialized empty Git repository in /Users/genzouw/hello/.git/

ステップ、変数ともに減らすことができました。

シェルスクリプトのファイル名を取得できる

$_ 特殊変数を使うことで、Bash シェルスクリプト内でそのスクリプトのファイル名を取得できます。

以下のようなシンプルなシェルスクリプト main.sh を用意します。

#!/usr/bin/env bash

echo $_

実行してみます。

# 相対パスでカレントディレクトリ内の `main.sh` を実行
$ ./main.sh
./main.sh

# 絶対パスで `main.sh` を実行
$ /workdir/main.sh
/workdir/main.sh

ただし、シェバングを利用せずに bash コマンドの引数としてスクリプトを指定し実行すると、 bash コマンドのパスが出力されます。

$ bash main.sh
/usr/bin/bash

このような挙動のため、別の方法でシェルスクリプトのファイルパスを取得するのは別の方法が良さそうです。

ひとこと

$_ 変数は便利ではありますが、事前に知識が必要になるため、万人向けのスクリプトを想定すると可読性が高いとは言えません。
使い所に注意が必要ですね。

2023-04-16Bash