리눅스 명령행 인자: 명령어 옵션과 따옴표, 옵션 끝 표시, $1, $# 받기

テスト環境RHEL系AlmaLinux 9.8bash 5.1rootアカウント
シェル$1$#--

Linux のコマンドライン引数(command-line argument)は、コマンド名の後ろに空白で区切って書き、プログラムに渡す値です。AlmaLinux 9 サーバーで、受け取った引数をそのまま表示するテスト用スクリプトにオプションや引用符、ワイルドカード、-- を渡してみたところ、引数を分けたのはシェルで、オプションを読んだのはそれぞれのコマンドでした。

下の出力は AlmaLinux 9.8 サーバーの root アカウントで bash 5.1 を使って実行した結果そのままです。テスト用スクリプトとサンプルファイルは別の作業フォルダーに作成し、パス /home/user/www は例の値です。

1️⃣ Linux のコマンドライン引数とは?

コマンドラインに [コマンド 引数1 引数2] のように書くと、シェルは空白を区切りにして単語を分けます。最初の単語が実行するプログラムになり、残りの単語は順番にそのプログラムの引数として渡されます。

渡された引数を目で確かめるため、作業フォルダーに args.sh を作成しました。$0 には実行した名前、$# には引数の個数、$1 以降には引数が順に入っています。角かっこは引数の始まりと終わりが見えるように付けています。

#!/bin/bash
echo "\$0 = $0"
echo "\$# = $#"
i=1
for a in "$@"; do
  echo "\$$i = [$a]"
  i=$((i+1))
done

スクリプトに実行権限を与えてから、a、b、c の 3 つの単語を渡して実行しました。

./args.sh a b c
$0 = ./args.sh
$# = 3
$1 = [a]
$2 = [b]
$3 = [c]

3 つの単語が $1、$2、$3 に入り、$# は 3 でした。bash の後ろにスクリプト名を書いて実行すると、$0 には書いた名前のまま args.sh が入ります。

bash args.sh a b c
$0 = args.sh
$# = 3
$1 = [a]
$2 = [b]
$3 = [c]

$0 だけが args.sh に変わり、3 つの引数と個数は前の結果と同じでした。

2️⃣ コマンドライン引数とコマンドオプション

Linux のコマンドは、ふつう [コマンド -オプション 引数] の順に書きます。オプションはコマンドの動き方を変え、引数はコマンドが扱うファイルやパス、値を決めます。

ls -l /home/user/www

シェルから見ると -l も引数の 1 つです。同じ単語を args.sh に渡すと、-l が $1 に、パスが $2 に入りました。

./args.sh -l /home/user/www
$0 = ./args.sh
$# = 2
$1 = [-l]
$2 = [/home/user/www]

-l をオプションとして読むのは ls です。そのため、同じ文字でもコマンドごとに意味が違います。head の -n は表示する行数を決め、ls の -n は所有者を名前ではなく番号で表示します。

オプションの中には、すぐ後ろの単語を自分の値として受け取るものがあります。find コマンドでは -type は f を、-name は "*.txt" を自分の値として使い、このようにオプションに付く値をオプション引数と呼びます。

find . -type f -name "*.txt"

このコマンドの先頭の . はオプションに付かない引数で、検索を始めるフォルダーを決めます。

3️⃣ Linux コマンドオプションの書き方

ダッシュ 1 つで始まる短いオプションは 1 文字で、複数をつなげて書けます。まず作業フォルダーの site フォルダーを [ls -l -a] で表示しました。

ls -l -a site
total 8
drwxr-xr-x 3 root root  52 Oct 28 16:00 .
drwxr-xr-x 3 root root 137 Oct 29 01:20 ..
-rw-r--r-- 1 root root  17 Oct 28 16:00 .htaccess
drwxr-xr-x 2 root root  23 Oct 28 16:00 css
-rw-r--r-- 1 root root  14 Oct 28 16:00 index.html

続いて、2 文字をつなげた [ls -la] の出力と diff で比べました。

diff <(ls -l -a site) <(ls -la site) && echo same
same

2 つの出力は 1 文字も違いませんでした。ダッシュ 2 つで始まる長いオプションは単語で書き、ls の --all は -a と同じオプションなので、[ls -l --all site] も同じ結果になりました。

長いオプションは、先頭部分だけ書いても 1 つに決まれば受け付けられます。--al は --all と --almost-all の 2 つに当てはまるため、ls は一覧を表示せず終了コード 2 で終わりました。

ls --al site
ls: option '--al' is ambiguous; possibilities: '--all' '--almost-all'
Try 'ls --help' for more information.

値を受け取るオプションには、いくつかの書き方があります。head で a.txt の先頭 2 行を表示するとき、短いオプションは値をつなげて [-n2] と書けます。

head -n2 a.txt
alpha
beta

長いオプションは等号で値をつないで [--lines=2] と書きます。

head --lines=2 a.txt
alpha
beta

空白で区切った [-n 2] と [--lines 2] も含めて、4 つの書き方すべてで alpha と beta の 2 行が表示されました。

ls、head、cat は C ライブラリの getopt_long 関数でオプションを読みます。3 つのプログラムファイルを strings で調べると、どれにもこの関数名が入っていました。

同じ規則をシェルで確かめるときは、util-linux の getopt コマンドを使います。-o の後ろに短いオプションを、-l の後ろに長いオプションを書き、文字の後ろのコロンは値を受け取るオプションという意味です。

getopt -o lan: -l all,lines: -- -la -n 2 --all a.txt
 -l -a -n '2' --all -- 'a.txt'

つなげて書いた -la は -l と -a に分かれ、-n 2 は -n と値 2 にまとめられました。オプションではない a.txt は、末尾の -- の後ろに移されました。

4️⃣ 引用符で囲んだコマンドライン引数とワイルドカード

空白を含むファイル名は、引用符で囲まないと 1 つの引数として渡せません。

./args.sh "my file.txt" report.txt
$0 = ./args.sh
$# = 2
$1 = [my file.txt]
$2 = [report.txt]

引用符なしで書くと my と file.txt が別々に分かれ、$# は 3 になりました。このまま ls や cat に渡すと、my と file.txt という 2 つのファイルを探すことになります。

./args.sh my file.txt report.txt
$0 = ./args.sh
$# = 3
$1 = [my]
$2 = [file.txt]
$3 = [report.txt]

ワイルドカードは、プログラムが受け取る前にシェルがファイル名に置き換えます。作業フォルダーで *.txt を渡すと、.txt で終わる 4 つのファイルが名前順に入りました。

./args.sh *.txt
$0 = ./args.sh
$# = 4
$1 = [a.txt]
$2 = [b.txt]
$3 = [my file.txt]
$4 = [report.txt]

引用符で囲んだ "*.txt" はシェルが置き換えないため、文字どおり 1 つの引数になりました。find の -name のように、プログラムがパターンを直接比べるオプションには、このように引用符で囲んで渡します。

./args.sh "*.txt"
$0 = ./args.sh
$# = 1
$1 = [*.txt]

空の引用符も空の引数 1 つとして渡されます。[./args.sh '' b] を実行すると $# は 2 で、$1 は空でした。

5️⃣ コマンドオプションの終わりの印(--)

-n という名前のファイルのように、ダッシュで始まる引数はコマンドがオプションとして読みます。そのファイルだけを入れた dash フォルダーで [ls -n] を実行すると、ls は -n をファイル名ではなく番号表示のオプションとして受け取り、フォルダーの一覧を表示しました。

ls -n
total 4
-rw-r--r-- 1 0 0 10 Oct 28 16:00 -n

-- の後ろに書いた引数は、ダッシュで始まってもオプションとして読まれません。[ls -- -n] は -n というファイル名だけを表示しました。

ls -- -n
-n

1 つのコマンドの中でも、-- の前と後ろでは同じ文字が違う読まれ方をします。cat に -n を 2 回渡すと、前の -n は行番号のオプション、-- の後ろの -n はファイル名として読まれ、行番号付きのファイルの内容が表示されました。

cat -n -- -n
     1	dash file

パスを付けて ./-n と書く方法もあり、この場合は引数がダッシュで始まらないため、同じ -n ファイルとして読まれます。

-- をオプションの終わりとして読むのも、コマンド側の規則です。オプションを読まない args.sh に渡すと、-- も $1 にそのまま入りました。

./args.sh -- -a
$0 = ./args.sh
$# = 2
$1 = [--]
$2 = [-a]

POSIX のユーティリティ規約は、オプション引数ではない最初の -- をオプションの終わりとして受け付けるよう定めています。そのため、この規約に従うコマンドでは、- で始まるファイル名を -- の後ろに書きます。

6️⃣ シェルスクリプトでコマンドライン引数を受け取る

シェルスクリプトは、受け取った引数を位置パラメーターと特殊パラメーターで読みます。C プログラムの main(int argc, char *argv[]) も同じ引数を受け取るので、両者を並べると次のようになります。

パラメーター入っている値C 言語の main 関数
$0実行したスクリプト名argv[0]
$1 ~ $91 番目から 9 番目の引数argv[1] ~ argv[9]
${10}10 番目の引数からは中かっこで囲むargv[10]
$#引数の個数・$0 は数えないargc - 1
"$@"引数すべて・1 つずつ別々argv[1] から最後まで
"$*"引数すべてを空白でつないだ 1 つ—

Python プログラムには、同じ引数が sys.argv のリストとして渡されます。[python3 -c] で引数を 3 つ渡してみると、引用符で囲んだ my file.txt がリストの 1 つの要素に入り、最初の要素には -c が入りました。

python3 -c 'import sys; print(sys.argv)' a "my file.txt" -l
['-c', 'a', 'my file.txt', '-l']

"$@" と "$*" は、ダブルクォートで囲んだときに結果が変わります。この違いを見るため、2 つの書き方を順に表示する star.sh を作成しました。

#!/bin/bash
echo 'with "$@"'
printf '  [%s]\n' "$@"
echo 'with "$*"'
printf '  [%s]\n' "$*"

star.sh に a、"b c"、d の 3 つの引数を渡して実行しました。

./star.sh a "b c" d
with "$@"
  [a]
  [b c]
  [d]
with "$*"
  [a b c d]

"$@" は 3 つの引数を別々に渡し、"$*" は空白でつないで 1 つにして渡しました。

そのため、受け取った引数を別のコマンドにそのまま渡すときは "$@" を使います。

shift は $1 を捨て、残りの引数を 1 つずつ前に詰めます。オプションを 1 つ先に読み、残りをファイルの一覧として扱うスクリプトで使います。

shift の前後で $1 と $# を表示する shift.sh を作成しました。

#!/bin/bash
echo "before shift: \$1 = $1, \$# = $#"
shift
echo "after shift:  \$1 = $1, \$# = $#"

shift.sh に -v、a.txt、b.txt の 3 つの引数を渡して実行しました。

./shift.sh -v a.txt b.txt
before shift: $1 = -v, $# = 3
after shift:  $1 = a.txt, $# = 2

10 番目の引数からは ${10} のように中かっこで囲みます。$10 と ${10} を並べて表示する ten.sh を作成しました。

#!/bin/bash
echo "\$10 = $10"
echo "\${10} = ${10}"

ten.sh に a から k までの引数 11 個を渡しました。

./ten.sh a b c d e f g h i j k
$10 = a0
${10} = j

$10 は $1 の後ろに 0 が付いた a0 になり、${10} は 10 番目の引数 j になりました。

🔲 コマンドライン引数シミュレーター

下のシミュレーターでは、args.sh に引用符やワイルドカード、-- を入れて渡せるほか、ls と getopt がオプションを読む仕組みや、star.sh と shift.sh が引数を受け取る仕組みも、自分で入力して試せます。

コマンドライン引数シミュレーターbash 5.1
[root@server work]#
ブラウザーの中だけで動く仮想 AlmaLinux サーバーです。args.sh は受け取った引数を番号付きで表示し、↑↓ で前に使ったコマンドを呼び出せます。

🔢 FAQ & おすすめコンテンツ

引数と環境変数を合わせた長さの上限は [getconf ARG_MAX] で確認でき、AlmaLinux 9.8 サーバーでは 2097152 バイトでした。この上限を超えるとプログラムは実行されず、[Argument list too long] エラーになります。ファイルがとても多いときは、ワイルドカードで一度に渡さず、find の -exec や xargs で分けて渡します。

引数(argument)はコマンドを実行するときに実際に渡す値で、パラメーター(parameter)はその値を受け取る側の名前です。シェルスクリプトでは、$1、$2 のような位置パラメーターが渡された引数を受け取ります。

bash に組み込まれた getopts は、-v のような短いオプションを 1 つずつ読みます。長いオプションは読まないため、--verbose のような長いオプションまで受け付けるときは、上で使った getopt コマンドで先に引数を整理します。

ℹ️ 提携について
当サイトのコンテンツにはアフィリエイトリンクが含まれています。訪問者がこのリンクを通じて商品やサービスを購入すると、当サイトは販売元から手数料を受け取ります。この過程において、購入者が支払う金額(イベント割引適用で金額が下がります↓)は上昇しません。掲載されている価格・割引・在庫情報は作成時点のものであり、実際とは異なる場合がありますので、ご購入前に販売元にて最終確認をお願いいたします。商品の選定および評価は独自の基準に基づいて行われており、手数料の支払いの有無は紹介順や評価内容に影響を与えません。

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

人間であることを証明してください: 7   +   8   =