はじめに

こんにちは!今回はshiftコマンドについて解説します。

shiftは、位置パラメータ($1, $2, $3…)を左にずらすコマンドです。スクリプトで複数の引数を順番に処理したい時に使います。

shiftコマンドとは

shiftは、位置パラメータを左にシフトする組み込みコマンドです。

例えば、shiftを実行すると、$2が$1になり、$3が$2になり…という感じで全部が1つ左にずれます。元の$1は消えます。これを使うと、引数を1つずつ処理していけます。

基本構文

1
shift [n]
  • n: シフトする数(省略時は1)

使用例

例1: 基本的なshift

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/bash

echo "第1引数: $1"
echo "第2引数: $2"
echo "第3引数: $3"

shift

echo "shift後の第1引数: $1"
echo "shift後の第2引数: $2"
echo "shift後の第3引数: $3"

実行:

1
./script.sh apple banana orange

実行結果:

1
2
3
4
5
6
第1引数: apple
第2引数: banana
第3引数: orange
shift後の第1引数: banana
shift後の第2引数: orange
shift後の第3引数:

appleが消えて、全部が1つ左にずれました。

例2: ループで全引数を処理

1
2
3
4
5
6
#!/bin/bash

while [ $# -gt 0 ]; do
  echo "処理中: $1"
  shift
done

実行:

1
./script.sh file1.txt file2.txt file3.txt

実行結果:

1
2
3
処理中: file1.txt
処理中: file2.txt
処理中: file3.txt

$#は引数の数なので、これが0より大きい間ループします。

例3: 複数シフト

1
2
3
4
5
6
7
8
9
#!/bin/bash

echo "最初の3つの引数:"
echo "$1 $2 $3"

shift 3  # 3つ分シフト

echo "shift 3 後:"
echo "$1 $2 $3"

実行:

1
./script.sh a b c d e f

実行結果:

1
2
3
4
最初の3つの引数:
a b c
shift 3 後:
d e f

数値を指定すると、その数だけシフトできます。

例4: オプション解析

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash

VERBOSE=false
OUTPUT=""

while [ $# -gt 0 ]; do
  case "$1" in
    -v|--verbose)
      VERBOSE=true
      shift
      ;;
    -o|--output)
      OUTPUT="$2"
      shift 2  # オプションと値の2つをシフト
      ;;
    *)
      echo "不明なオプション: $1"
      exit 1
      ;;
  esac
done

echo "Verbose: $VERBOSE"
echo "Output: $OUTPUT"

実行:

1
./script.sh -v -o result.txt

実行結果:

1
2
Verbose: true
Output: result.txt

オプション解析で超よく使います。

例5: 引数の数をカウント

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/bash

echo "引数の数: $#"

count=0
while [ $# -gt 0 ]; do
  count=$((count + 1))
  echo "${count}番目: $1"
  shift
done

echo "合計: $count 個"

実行:

1
./script.sh apple banana orange

実行結果:

1
2
3
4
5
引数の数: 3
1番目: apple
2番目: banana
3番目: orange
合計: 3 個

例6: 最初の引数を特別扱い

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/bash

COMMAND=$1
shift  # コマンドを取り出してシフト

echo "コマンド: $COMMAND"
echo "残りの引数:"

for arg in "$@"; do
  echo "  - $arg"
done

実行:

1
./script.sh install package1 package2 package3

実行結果:

1
2
3
4
5
コマンド: install
残りの引数:
  - package1
  - package2
  - package3

最初の引数をコマンドとして扱って、残りをオプションとして処理するパターン。

例7: shiftのエラーチェック

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#!/bin/bash

if [ $# -lt 2 ]; then
  echo "Error: 引数が足りません"
  exit 1
fi

NAME=$1
shift

AGE=$1
shift

echo "名前: $NAME"
echo "年齢: $AGE"
echo "その他: $@"

実行:

1
./script.sh Taro 25 Tokyo Japan

実行結果:

1
2
3
名前: Taro
年齢: 25
その他: Tokyo Japan

例8: shift不可能な場合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/bash

echo "引数の数: $#"

shift 10  # 引数が10個ない場合

if [ $? -ne 0 ]; then
  echo "shiftに失敗しました"
else
  echo "shiftに成功"
fi

実行:

1
./script.sh a b c

実行結果:

1
2
引数の数: 3
shiftに失敗しました

shiftする数より引数が少ないとエラーになります。

Tips・注意点

  • $@と$*の違い: shiftはどちらにも影響する

    1
    2
    
    shift
    echo "$@"  # shift後の引数
    
  • 引数の数($#)は自動更新: shiftすると$#も減る

    1
    2
    3
    
    echo "Before: $#"
    shift
    echo "After: $#"
    
  • 元に戻せない: shiftした引数は復元できない

    1
    2
    3
    
    FIRST=$1  # 保存しておく
    shift
    # $1はもう戻せない
    
  • 空の時にshiftするとエラー: 引数がない時の対策が必要

    1
    2
    3
    
    if [ $# -gt 0 ]; then
      shift
    fi
    
  • 関数内でも使える: 関数の引数もshiftできる

    1
    2
    3
    4
    5
    
    my_func() {
      echo "First: $1"
      shift
      echo "Rest: $@"
    }
    

実践的な使い方

コマンドラインオプションの解析

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!/bin/bash

# デフォルト値
INPUT=""
OUTPUT=""
VERBOSE=false

# ヘルプメッセージ
show_help() {
  echo "使い方: $0 -i INPUT -o OUTPUT [-v]"
  echo "  -i INPUT   入力ファイル"
  echo "  -o OUTPUT  出力ファイル"
  echo "  -v         詳細モード"
}

# オプション解析
while [ $# -gt 0 ]; do
  case "$1" in
    -i|--input)
      INPUT="$2"
      shift 2
      ;;
    -o|--output)
      OUTPUT="$2"
      shift 2
      ;;
    -v|--verbose)
      VERBOSE=true
      shift
      ;;
    -h|--help)
      show_help
      exit 0
      ;;
    *)
      echo "Error: 不明なオプション $1"
      show_help
      exit 1
      ;;
  esac
done

# 必須パラメータのチェック
if [ -z "$INPUT" ] || [ -z "$OUTPUT" ]; then
  echo "Error: 入力ファイルと出力ファイルは必須です"
  show_help
  exit 1
fi

echo "入力: $INPUT"
echo "出力: $OUTPUT"
echo "詳細モード: $VERBOSE"

複数ファイルの処理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash

if [ $# -eq 0 ]; then
  echo "Error: ファイルを指定してください"
  exit 1
fi

count=0
while [ $# -gt 0 ]; do
  file="$1"

  if [ -f "$file" ]; then
    echo "処理中: $file"
    # ファイル処理
    wc -l "$file"
    count=$((count + 1))
  else
    echo "Warning: $file が見つかりません"
  fi

  shift
done

echo "合計 $count ファイル処理しました"

サブコマンドの実装

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/bin/bash

SCRIPT_NAME=$(basename "$0")

# サブコマンド: start
cmd_start() {
  echo "Starting service..."
  # 起動処理
}

# サブコマンド: stop
cmd_stop() {
  echo "Stopping service..."
  # 停止処理
}

# サブコマンド: restart
cmd_restart() {
  cmd_stop
  cmd_start
}

# メイン処理
if [ $# -eq 0 ]; then
  echo "使い方: $SCRIPT_NAME {start|stop|restart}"
  exit 1
fi

COMMAND=$1
shift  # コマンド名を取り出してシフト

case "$COMMAND" in
  start)
    cmd_start "$@"
    ;;
  stop)
    cmd_stop "$@"
    ;;
  restart)
    cmd_restart "$@"
    ;;
  *)
    echo "Error: 不明なコマンド: $COMMAND"
    exit 1
    ;;
esac

引数のグループ処理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#!/bin/bash

# ペアで処理(キーと値)
while [ $# -gt 0 ]; do
  key="$1"
  value="$2"

  if [ $# -lt 2 ]; then
    echo "Error: $key に対応する値がありません"
    exit 1
  fi

  echo "設定: $key = $value"

  shift 2  # 2つずつシフト
done

実行:

1
./script.sh name Taro age 25 city Tokyo

リストの最初と残り

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash

if [ $# -eq 0 ]; then
  echo "Error: 引数が必要です"
  exit 1
fi

first=$1
shift

echo "最初の要素: $first"

if [ $# -gt 0 ]; then
  echo "残りの要素:"
  for item in "$@"; do
    echo "  - $item"
  done
else
  echo "残りの要素はありません"
fi

まとめ

今回はshiftコマンドについて解説しました。

ポイント:

  • shiftで位置パラメータを左にシフトできる
  • 引数を1つずつ処理するループでよく使う
  • shift nで複数個シフト可能
  • オプション解析の実装に便利
  • $#(引数の数)は自動的に減る
  • shiftした引数は元に戻せない

シェルスクリプトでコマンドラインオプションを処理する時には、shiftが必須です。whileループと組み合わせて、柔軟なオプション解析を実装してみてください。

次回もLinuxコマンドの学習を続けていきましょう!