【Shell Script】コマンドライン引数の受け取り方(1・@・$#)

Shell Script

こんにちは、かつコーチです。

「スクリプトの中身を毎回書き換えて実行している」。
それでは自動化のメリットが半減してしまいます。
この記事では、実行時に外から値を渡せるコマンドライン引数の受け取り方を、$1$@$#を中心に初心者向けに解説します。
引数を使いこなせると、1つのスクリプトを状況に応じて使い回せるようになります。

コマンドライン引数とは?

スクリプトに渡す「お使いのメモ」

コマンドライン引数とは、スクリプトを実行するときにコマンドの後ろに書き添えて渡す値のことです。

たとえるなら、家族に頼む「お使いのメモ」に近いものです。
「牛乳」とだけ書いたメモを渡せば牛乳を買ってきてもらえますし、「牛乳、卵、パン」と書けば3つ買ってきてもらえます。
同じように、スクリプトに渡す引数を変えるだけで、スクリプトの中身を書き換えずに動作対象を変えられます。

./backup.sh /var/log

この例では、/var/logbackup.shに渡された引数です。

なぜ引数が必要なのか

引数を使わないと、「バックアップ対象のディレクトリ」のようにスクリプトごとに変わる値も、スクリプトの中に直接書き込むしかありません。
対象が変わるたびにスクリプトを書き換えるのは非効率ですし、書き換えミスの原因にもなります。
引数を受け取れるようにしておけば、スクリプト本体は共通のまま、実行時に渡す値だけを変えて使い回せます。

基本の書き方

・・…で個別の引数を受け取る

引数は渡された順に、$1$2$3…という位置パラメータに自動で入ります。

#!/bin/bash

echo "1番目の引数: $1"
echo "2番目の引数: $2"
$ ./greet.sh 田中 山田
1番目の引数: 田中
2番目の引数: 山田

$#で引数の個数を確認する

$#には、渡された引数の個数が入ります。
引数の数が足りているかをチェックする用途でよく使います。

#!/bin/bash

if [ "$#" -lt 1 ]; then
  echo "使い方: $0 対象ディレクトリ"
  exit 1
fi

echo "引数の個数: $#"
echo "対象ディレクトリ: $1"

@・*ですべての引数をまとめて受け取る

$@$*は、渡されたすべての引数をまとめて表す変数です。
基本的には"$@"(ダブルクォートで囲む)を使うのが定石です。

#!/bin/bash

for arg in "$@"
do
  echo "引数: $arg"
done
$ ./list.sh apple "orange juice" banana
引数: apple
引数: orange juice
引数: banana

よくあるつまずきポイント・エラー対処

“$@”にクォートを付けず引数が分割される

複数のファイルをまとめてコピーするスクリプトを作ったとき、スペースを含むファイル名がうまく扱えず困ったことがあります。

❌Before(つまずいた実例)

#!/bin/bash

for file in $@
do
  echo "処理対象: $file"
done
$ ./process.sh "report draft.txt" summary.txt
処理対象: report
処理対象: draft.txt
処理対象: summary.txt

「report draft.txt」という1つの引数のはずが、スペースの部分で2つに分割されてしまいました。

✅After(解決方法)

原因は、クォートなしの$@が単語ごとに分割(ワードスプリッティング)されることでした。
"$@"とダブルクォートで囲むことで、引数の境界がそのまま保たれるよう修正しました。

#!/bin/bash

for file in "$@"
do
  echo "処理対象: $file"
done
$ ./process.sh "report draft.txt" summary.txt
処理対象: report draft.txt
処理対象: summary.txt

「引数をループやコマンドに渡すときは、必ず"$@"とクォートする」というのは、実務でも頻出する注意点です。

応用・一歩先の使い方

デフォルト値を設定する(${1:-値})

引数が省略された場合に備えて、デフォルト値を設定しておくと安全です。

#!/bin/bash

# 引数が省略された場合は/var/logを使う
target_dir="${1:-/var/log}"

echo "対象ディレクトリ: $target_dir"

shiftで引数をずらしながら処理する

shiftを使うと、$1を1つずつ消費しながら残りの引数を順番に処理できます。
サブコマンド形式のスクリプトでよく使うテクニックです。

#!/bin/bash

command="$1"
shift  # $1を消費し、$2以降を$1・$2…に繰り上げる

case "$command" in
  start)
    echo "起動オプション: $@"
    ;;
  *)
    echo "未対応のコマンドです: $command"
    ;;
esac

まとめ

この記事のポイント

  • $1$2…は渡された順の個別の引数、$#は引数の個数を表す
  • 全引数をまとめて扱うときは"$@"をダブルクォートで囲んで使う
  • クォートなしの$@はスペースで分割されてしまうため、原則"$@"を使う
  • ${1:-デフォルト値}で引数省略時の初期値を設定できる

次に読むべき記事

引数の次は、コマンドの入出力の基本である「標準入力・標準出力・標準エラー出力の仕組み」を読んでみてください。

タグ: Shell, 初心者向け, 引数・入出力

タイトルとURLをコピーしました