シェルスクリプトの変数・if・for|くり返し作業を自動化【初心者向け】

前の記事では、コマンドを並べたシェルスクリプトを作り、日付つきのバックアップを1回の実行で取れるようにしました。でも、あのスクリプトは「いつも同じこと」しかできません。

たとえば、ダウンロードフォルダにたまったたくさんのファイルを、種類ごとのフォルダに一気に分けられたら便利だと思いませんか。手でやると時間のかかる作業も、スクリプトならあっという間に終わります。そのときに使うのが、今回の 変数・if・for です。

この記事では、「渡したものによって動きを変える」「たくさんのファイルに同じことをくり返す」スクリプトを、練習用のファイルで作っていきます。

💡
この記事でわかること
  • 変数の作り方と使い方(= の前後にスペースを入れない)
  • ' と " の違い
  • スクリプトに値を渡す $1(引数)
  • if で、ファイルがあるかどうかで動きを変える方法
  • for で、たくさんのファイルに同じことをくり返す方法
  • ファイルを拡張子(=ファイル名の最後の .txt や .py の部分)ごとのフォルダに分けるスクリプトの作り方
🔰
この記事の前提
  • nano でスクリプトを書き、chmod u+x して ./ファイル名 で動かせる
  • #!/bin/bash・set -e・bash -x の意味がわかる
  • ワイルドカード(*)の使い方がわかる

まだの方は、前の記事「Linuxのシェルスクリプト入門|いつもの手順を1ファイルにまとめる【初心者向け】」から読むのがおすすめです。

💡
用語メモ
  • APIキー:API を使うときに必要な、合言葉のような文字列。人に見せてはいけません
  • トークン:ログインした状態や、使ってよい範囲を表す文字列。APIキーと同じく、パスワードと同じように人に見せてはいけません
  • コマンド:パソコンへの指示の言葉。ターミナルに打って Enter で実行します
  • シェルスクリプト:ターミナルに打つコマンドを、順番にファイルに書いておいたもの。bash が上から1行ずつ実行します

用語で迷ったら、連載のまとめ記事の「よく出てくる用語ミニ辞典」でも確かめられます。


結論:3つの部品で、スクリプトが「考えて動く」ようになる

部品 役割 書き方の例
変数 値に名前をつけて覚えておく name="kaito" → "$name"
引数 動かすときに値を渡す ./greet.sh kaito → "$1"
if 条件によって動きを変える if [ -f "$file" ]; then … fi
for 同じことをくり返す for f in *.txt; do … done

if と for の流れ

準備:練習用のディレクトリを作る

今回は ~/linux-practice/script-test/if-for の中で練習します。

  • 1
  • 2
  • 3
mkdir -p ~/linux-practice/script-test/if-for
cd ~/linux-practice/script-test/if-for
pwd

🖥️
この記事の出力例について

ここから先の出力例は、Debian 13での実行例です(ユーザー名 kaito・パソコン名 demo のダミー環境)。UbuntuやWSL(=Windows の中で Linux を動かせる、Microsoft のしくみ)では、表示が少し違うことがあります。

(例)

  • 1
  • 2
kaito@demo:~/linux-practice/script-test/if-for$ pwd
/home/kaito/linux-practice/script-test/if-for

変数:値に名前をつける

まずはターミナルで直接ためしてみましょう。変数は 名前=値 で作り、$名前 で取り出します。

  • 1
  • 2
name="kaito"
echo "こんにちは、$name さん"

(例)

  • 1
  • 2
  • 3
kaito@demo:~/linux-practice/script-test/if-for$ name="kaito"
kaito@demo:~/linux-practice/script-test/if-for$ echo "こんにちは、$name さん"
こんにちは、kaito さん

いちばん多いまちがいが、= の前後にスペースを入れてしまうことです。わざとやってみます。

  • 1
name = "kaito"

(例)

  • 1
  • 2
kaito@demo:~/linux-practice/script-test/if-for$ name = "kaito"
-bash: name: command not found

先頭が -bash: になるのは、ログインシェル(=ログインしたときに最初に動くシェル)で動いているときの表示です(ふだんのターミナルでは bash: のこともあります)。日本語の環境では -bash: name: コマンドが見つかりません と表示されます。

スペースを入れると、シェルは「name というコマンドに、= と kaito を渡して」と読んでしまいます。変数を作るときは、= の前後をくっつけて書きましょう。

' と " の違い

"(ダブルクォート)の中では変数が中身に置きかわり、'(シングルクォート)の中では、書いたとおりの文字になります。

  • 1
  • 2
echo "ダブル:$name"
echo 'シングル:$name'

(例)

  • 1
  • 2
  • 3
  • 4
kaito@demo:~/linux-practice/script-test/if-for$ echo "ダブル:$name"
ダブル:kaito
kaito@demo:~/linux-practice/script-test/if-for$ echo 'シングル:$name'
シングル:$name

引数:スクリプトに値を渡す

スクリプトを動かすときに、うしろに書いた値を受け取れます。1つ目が $1、2つ目が $2、渡した数は $# に入ります。nano greet.sh で、次の中身を書いて保存します。

  • 1
  • 2
  • 3
  • 4
  • 5
#!/bin/bash
# 渡された名前にあいさつする
name="$1"
echo "渡された数:$#"
echo "こんにちは、$name さん"

  • 1
  • 2
  • 3
chmod u+x greet.sh
./greet.sh kaito
./greet.sh

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
kaito@demo:~/linux-practice/script-test/if-for$ chmod u+x greet.sh
kaito@demo:~/linux-practice/script-test/if-for$ ./greet.sh kaito
渡された数:1
こんにちは、kaito さん
kaito@demo:~/linux-practice/script-test/if-for$ ./greet.sh
渡された数:0
こんにちは、 さん

Debian 13での実行画面

何も渡さないと、名前が空のままあいさつしてしまいました。こういうときに使うのが、次の if です。


if:条件によって動きを変える

if の基本の形はこうです。

  • 1
  • 2
  • 3
  • 4
  • 5
if [ 条件 ]; then
  条件に合うときのコマンド
else
  合わないときのコマンド
fi

よく使う条件は次のとおりです。

条件 意味
[ -f "$file" ] ファイルがある
[ -d "$dir" ] ディレクトリがある
[ -z "$name" ] 中身が空っぽ
[ "$a" = "$b" ] 文字が同じ
[ "$n" -gt 3 ] 数が 3 より大きい
[ ! -f "$file" ] ファイルがない(! は「ではない」)

ファイルがあるかどうかを確かめるスクリプトを作ってみましょう。nano check.sh で、次の中身を書いて保存します。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
#!/bin/bash
# 渡されたファイルがあるかどうかを確かめる
file="$1"

if [ -z "$file" ]; then
  echo "使い方:./check.sh ファイル名"
  exit 1
fi

if [ -f "$file" ]; then
  echo "$file はあります"
else
  echo "$file は見つかりません"
fi

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
chmod u+x check.sh
touch memo.txt
./check.sh memo.txt
./check.sh nothing.txt
./check.sh
echo "終わったときの番号:$?"

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
kaito@demo:~/linux-practice/script-test/if-for$ chmod u+x check.sh
kaito@demo:~/linux-practice/script-test/if-for$ touch memo.txt
kaito@demo:~/linux-practice/script-test/if-for$ ./check.sh memo.txt
memo.txt はあります
kaito@demo:~/linux-practice/script-test/if-for$ ./check.sh nothing.txt
nothing.txt は見つかりません
kaito@demo:~/linux-practice/script-test/if-for$ ./check.sh
使い方:./check.sh ファイル名
kaito@demo:~/linux-practice/script-test/if-for$ echo "終わったときの番号:$?"
終わったときの番号:1

exit 1 は「ここでスクリプトを終わりにして、失敗の番号 1 を返す」という意味です。前の記事で見た $? に、その番号が入ります。

💡
[ と ] の内側には、必ずスペースを入れる

if [-f "$file"] のように、[ や ] にくっつけて書くと、エラーになります。[ -f "$file" ] のように、カッコの内側にスペースを1つずつ入れるのがルールです。うまく動かないときは、まずここを見直してみてください。


for:同じことをくり返す

for は、並べたものを1つずつ取り出して、同じことをくり返します。まずはターミナルで直接ためしてみましょう。

  • 1
  • 2
  • 3
for i in 1 2 3; do
  echo "$i 回目"
done

(例)

  • 1
  • 2
  • 3
  • 4
kaito@demo:~/linux-practice/script-test/if-for$ for i in 1 2 3; do echo "$i 回目"; done
1 回目
2 回目
3 回目

※ 検証では、この for を1行にまとめて入力しました(; do・; done の形)。何行かに分けて打っても、結果は同じです。

ワイルドカードと組み合わせると、ファイルを1つずつ取り出せます。練習用のファイルを作ってからためします。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
mkdir -p inbox
cd inbox
touch report_1.txt report_2.txt photo_1.jpg photo_2.jpg data.csv
ls
for f in *.txt; do
  echo "見つけたファイル:$f"
done

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
kaito@demo:~/linux-practice/script-test/if-for$ mkdir -p inbox
kaito@demo:~/linux-practice/script-test/if-for$ cd inbox
kaito@demo:~/linux-practice/script-test/if-for/inbox$ touch report_1.txt report_2.txt photo_1.jpg photo_2.jpg data.csv
kaito@demo:~/linux-practice/script-test/if-for/inbox$ ls
data.csv  photo_1.jpg  photo_2.jpg  report_1.txt  report_2.txt
kaito@demo:~/linux-practice/script-test/if-for/inbox$ for f in *.txt; do echo "見つけたファイル:$f"; done
見つけたファイル:report_1.txt
見つけたファイル:report_2.txt

※ 検証では、この for を1行にまとめて入力しました(; do・; done の形)。何行かに分けて打っても、結果は同じです。


実用編:ファイルを拡張子ごとのフォルダに分ける

いよいよ、変数・if・for を全部使います。inbox の中のファイルを、txt・jpg・csv のフォルダに分けるスクリプトです。

まずは「何が起きるか」だけ表示してみる

いきなりファイルを動かす前に、動かす予定だけを表示して確かめるのが安全です。

  • 1
  • 2
  • 3
for f in *; do
  echo "$f → ${f##*.}/"
done

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
kaito@demo:~/linux-practice/script-test/if-for/inbox$ for f in *; do echo "$f → ${f##*.}/"; done
data.csv → csv/
photo_1.jpg → jpg/
photo_2.jpg → jpg/
report_1.txt → txt/
report_2.txt → txt/

※ 検証では、この for を1行にまとめて入力しました(; do・; done の形)。何行かに分けて打っても、結果は同じです。

${f##*.} は「ファイル名の、最後の . より後ろだけ」を取り出す書き方です。photo_1.jpg なら jpg になります。

スクリプトにまとめる

予定どおりだったので、スクリプトにします。cd ~/linux-practice/script-test/if-for でひとつ上の if-for に戻ってから、nano organize.sh で次の中身を書いて保存します。

  • 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
#!/bin/bash
# 指定したフォルダの中のファイルを、拡張子ごとのフォルダに分ける
set -e
target="$1"

if [ -z "$target" ]; then
  echo "使い方:./organize.sh フォルダ名"
  exit 1
fi

if [ ! -d "$target" ]; then
  echo "$target というフォルダは見つかりません"
  exit 1
fi

cd "$target"
for f in *; do
  if [ -f "$f" ]; then
    ext="${f##*.}"
    mkdir -p "$ext"
    mv "$f" "$ext/"
    echo "$f → $ext/"
  fi
done
echo "整理が終わりました"

  • 1
  • 2
  • 3
  • 4
cd ~/linux-practice/script-test/if-for
chmod u+x organize.sh
./organize.sh inbox
ls -R inbox

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
kaito@demo:~/linux-practice/script-test/if-for$ chmod u+x organize.sh
kaito@demo:~/linux-practice/script-test/if-for$ ./organize.sh inbox
data.csv → csv/
photo_1.jpg → jpg/
photo_2.jpg → jpg/
report_1.txt → txt/
report_2.txt → txt/
整理が終わりました
kaito@demo:~/linux-practice/script-test/if-for$ ls -R inbox
inbox:
csv  jpg  txt

inbox/csv:
data.csv

inbox/jpg:
photo_1.jpg  photo_2.jpg

inbox/txt:
report_1.txt  report_2.txt

Debian 13での実行画面

if [ -f "$f" ] で「ファイルのときだけ」動かしているので、作ったフォルダ(txt など)はもう一度動かしても移動されません。もう一度動かして確かめてみましょう。

  • 1
  • 2
./organize.sh inbox
./organize.sh nothing-folder

(例)

  • 1
  • 2
  • 3
  • 4
kaito@demo:~/linux-practice/script-test/if-for$ ./organize.sh inbox
整理が終わりました
kaito@demo:~/linux-practice/script-test/if-for$ ./organize.sh nothing-folder
nothing-folder というフォルダは見つかりません

このスクリプトの弱点を知っておく

organize.sh は練習用なので、苦手なファイルがあります。自分のファイルに使う前に、次の3つを知っておきましょう。

  • 拡張子のないファイル(README など):${f##*.} は「最後の . より後ろ」を取り出しますが、. がないと名前がまるごと残ります。すると README という名前のフォルダを作ろうとして、同じ名前のファイルがすでにあるので失敗します。set -e があるのでそこで止まり、それより前のファイルだけが移動された、中途半端な状態になります。* の並び順はロケール(言語の設定)で変わり、順番によっては1つも動かないうちに止まります(下で試します)。
  • スクリプトと同じフォルダを指定したとき:./organize.sh . のように今いるフォルダを指定すると、organize.sh 自身も sh フォルダへ移動されてしまいます。整理したいファイルは、この記事のように別のフォルダ(inbox)に入れてから使いましょう。
  • . で始まる隠しファイル:for f in * の * は、隠しファイル(=名前が .(ピリオド)で始まるファイル)を含みません。そのため、隠しファイルは移動されずに残ります。

拡張子のない README を入れて試す

1つ目の弱点を、実際に確かめてみます。整理する前の inbox に、拡張子のない README が入っていたとします(上で整理したあとの inbox で試すと結果が変わるので、別のフォルダで試すときは、inbox を inbox2 などに変えて打ってください)。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
mkdir -p inbox
touch inbox/report_1.txt inbox/report_2.txt inbox/photo_1.jpg inbox/photo_2.jpg inbox/data.csv
echo "最初に読むファイル" > inbox/README
ls inbox
chmod u+x organize.sh
./organize.sh inbox
echo $?
ls -R inbox

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
kaito@demo:~/linux-practice/script-test/if-for$ mkdir -p inbox
kaito@demo:~/linux-practice/script-test/if-for$ touch inbox/report_1.txt inbox/report_2.txt inbox/photo_1.jpg inbox/photo_2.jpg inbox/data.csv
kaito@demo:~/linux-practice/script-test/if-for$ echo "最初に読むファイル" > inbox/README
kaito@demo:~/linux-practice/script-test/if-for$ ls inbox
README  data.csv  photo_1.jpg  photo_2.jpg  report_1.txt  report_2.txt
kaito@demo:~/linux-practice/script-test/if-for$ chmod u+x organize.sh
kaito@demo:~/linux-practice/script-test/if-for$ ./organize.sh inbox
mkdir: cannot create directory ‘README’: File exists
kaito@demo:~/linux-practice/script-test/if-for$ echo $?
1
kaito@demo:~/linux-practice/script-test/if-for$ ls -R inbox
inbox:
README  data.csv  photo_1.jpg  photo_2.jpg  report_1.txt  report_2.txt

Debian 13での実行画面

mkdir: cannot create directory ‘README’: File exists(「README というフォルダは作れません。同じ名前がもうあります」)で止まり、echo $? は 1(失敗)でした。日本語の設定(ja_JP.UTF-8)では、File exists のところが ファイルが存在します と表示されます。

ls -R inbox を見ると、ファイルは1つも動いていません。この環境(C.UTF-8)では、* が大文字の名前を先に並べるので、README がいちばん最初に処理されて、そこで止まったからです。日本語の ja_JP.UTF-8 でも同じ並びで、0個のまま止まりました。

一方、en_US.UTF-8 では、大文字と小文字をまぜて並べるので、README は4番目になります。そのときは、前の3つだけが移動された「途中まで」の状態で止まります。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
mkdir -p inbox3
touch inbox3/report_1.txt inbox3/report_2.txt inbox3/photo_1.jpg inbox3/photo_2.jpg inbox3/data.csv
echo "最初に読むファイル" > inbox3/README
for L in C.UTF-8 ja_JP.UTF-8 en_US.UTF-8; do (cd inbox3 && LANG=$L bash -c 'echo "$LANG: " *'); done
LANG=en_US.UTF-8 ./organize.sh inbox3
echo $?
ls -R inbox3

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
kaito@demo:~/linux-practice/script-test/if-for$ mkdir -p inbox3
kaito@demo:~/linux-practice/script-test/if-for$ touch inbox3/report_1.txt inbox3/report_2.txt inbox3/photo_1.jpg inbox3/photo_2.jpg inbox3/data.csv
kaito@demo:~/linux-practice/script-test/if-for$ echo "最初に読むファイル" > inbox3/README
kaito@demo:~/linux-practice/script-test/if-for$ for L in C.UTF-8 ja_JP.UTF-8 en_US.UTF-8; do (cd inbox3 && LANG=$L bash -c 'echo "$LANG: " *'); done
C.UTF-8:  README data.csv photo_1.jpg photo_2.jpg report_1.txt report_2.txt
ja_JP.UTF-8:  README data.csv photo_1.jpg photo_2.jpg report_1.txt report_2.txt
en_US.UTF-8:  data.csv photo_1.jpg photo_2.jpg README report_1.txt report_2.txt
kaito@demo:~/linux-practice/script-test/if-for$ LANG=en_US.UTF-8 ./organize.sh inbox3
data.csv → csv/
photo_1.jpg → jpg/
photo_2.jpg → jpg/
mkdir: cannot create directory ‘README’: File exists
kaito@demo:~/linux-practice/script-test/if-for$ echo $?
1
kaito@demo:~/linux-practice/script-test/if-for$ ls -R inbox3
inbox3:
README  csv  jpg  report_1.txt  report_2.txt

inbox3/csv:
data.csv

inbox3/jpg:
photo_1.jpg  photo_2.jpg

Debian 13での実行画面

data.csv・photo_1.jpg・photo_2.jpg の3つだけが移動されて、README と report_*.txt は残りました。どこで止まるかは並び順しだい、というのがわかります(en_US.UTF-8 が入っていない環境では、この並びになりません)。

拡張子のないファイルに備えるなら、ext="${f##*.}" の次の行に if [ "$ext" = "$f" ]; then ext="noext"; fi を足すと、拡張子のないファイルは noext というフォルダにまとめられます。取り出した結果が名前と同じ、つまり . がなかったときだけ、行き先を変えるしくみです。

nano organize.sh で ext="${f##*.}" の次の行にこの1行を足して保存し、さっきの inbox でもう一度動かしてみます。grep -n -A1 "ext=" organize.sh は、足した場所を行番号つきで確かめるためのコマンドです。

  • 1
  • 2
  • 3
  • 4
grep -n -A1 "ext=" organize.sh
./organize.sh inbox
echo $?
ls -R inbox

(例)

  • 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
kaito@demo:~/linux-practice/script-test/if-for$ grep -n -A1 "ext=" organize.sh
19:    ext="${f##*.}"
20:    if [ "$ext" = "$f" ]; then ext="noext"; fi
21-    mkdir -p "$ext"
kaito@demo:~/linux-practice/script-test/if-for$ ./organize.sh inbox
README → noext/
data.csv → csv/
photo_1.jpg → jpg/
photo_2.jpg → jpg/
report_1.txt → txt/
report_2.txt → txt/
整理が終わりました
kaito@demo:~/linux-practice/script-test/if-for$ echo $?
0
kaito@demo:~/linux-practice/script-test/if-for$ ls -R inbox
inbox:
csv  jpg  noext  txt

inbox/csv:
data.csv

inbox/jpg:
photo_1.jpg  photo_2.jpg

inbox/noext:
README

inbox/txt:
report_1.txt  report_2.txt

Debian 13での実行画面

README → noext/ と表示されて、最後の 整理が終わりました まで進み、echo $? は 0(成功)になりました。

🚫
変数を使った rm -rf は、変数が空のときに大事故になる(文章だけで説明します)

スクリプトの中で rm -rf "$dir/" のように書くと、もし $dir が空っぽだった場合、rm -rf "/" と同じ意味になり、パソコンの中身をまるごと消そうとしてしまいます。実際に、これでデータが消えた事故も知られています。この記事では試しません。どうしても使うときは、上の organize.sh のように if [ -z "$dir" ] で空のときに止める、${dir:?} と書いて空ならエラーにする、などの守りを入れましょう。そもそも、スクリプトで消すより mv でゴミ箱代わりのフォルダに移すほうが安全です。

🤖 詰まったらAIに聞こう:if や for がうまく動かない・やりたいことを形にしたい

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
Linuxの初心者です。bash のシェルスクリプトについて教えてください。
次のスクリプトが思ったとおりに動きません。原因と直し方を、やさしく説明してください。
ファイルを消したり上書きしたりする行がある場合は、先に教えてください。
直したスクリプトには、何が起きるかだけ表示する「お試しモード」もつけてください。

【使っている環境】WSLのUbuntu など
【やりたいこと】例:フォルダの中の .txt だけを別のフォルダに移したい
【スクリプトの中身(秘密情報は***に置き換え済み)】ここに貼る
【動かし方】例:./organize.sh inbox
【表示されたエラー、または bash -x の結果】ここに貼る

🔒
AIに貼る前に:秘密情報やパスワードは貼らない

スクリプトの変数に、APIキー、トークン、パスワードを直接書いていませんか? AI に貼る前に、それらを必ず「***」に置き換えてください。また、ls の結果にお客さまの名前など個人情報が入ったファイル名がある場合は、ダミーの名前に置き換えてから貼りましょう。


後片づけ

練習で作ったファイルは、~/linux-practice/script-test/if-for の中だけにあります。いらなくなったら、場所を確かめてから消しましょう。

  • 1
  • 2
  • 3
  • 4
cd ~/linux-practice/script-test
ls
rm -r if-for
ls

(例)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
kaito@demo:~/linux-practice/script-test/if-for$ cd ~/linux-practice/script-test
kaito@demo:~/linux-practice/script-test$ ls
backup  backup-notes.sh  crlf.sh  hello.sh  if-for  notes
kaito@demo:~/linux-practice/script-test$ rm -r if-for
kaito@demo:~/linux-practice/script-test$ ls
backup  backup-notes.sh  crlf.sh  hello.sh  notes

よくある質問

Q. [ ] と [[ ]] は、どう違うのですか?

[[ ]] は bash が用意した、[ ] の便利版です。変数を " で囲み忘れても事故が起きにくいなどの違いがありますが、bash 以外のシェル(Debian の sh など)では使えません。この記事では、どのシェルでも使える [ ] で書いています。慣れるまでは [ ] と "$変数" の組み合わせを覚えておけば十分です。

Q. 変数を " で囲まないと、何が起きるのですか?

値にスペースが入っていると、別々の言葉に分かれてしまいます。たとえば my report.txt というファイルを mv $f txt/ で動かすと、my と report.txt という2つのファイルを動かそうとして失敗します。mv "$f" txt/ なら、1つの名前として扱われます。

Q. 空のフォルダで for f in * を動かすと、どうなりますか?

ファイルが1つもないと、bash は * を置きかえずに、* という文字のまま f に入れます。organize.sh では if [ -f "$f" ] で「ファイルのときだけ」動かしているので、* という名前のファイルはなく、何もせずに「整理が終わりました」と表示されます。この -f の確認は、こうした場面の守りにもなっています。


まとめ

  • 変数は 名前=値 で作る。= の前後にスペースを入れない
  • " の中では変数が置きかわり、' の中では書いたとおりになる
  • 変数を使うときは "$name" のように " で囲む
  • $1・$2 でスクリプトに渡した値を受け取れる。$# は渡した数
  • if [ 条件 ]; then … fi で動きを変える。[ ] の内側にはスペース
  • for f in *.txt; do … done でファイルを1つずつ処理できる
  • ファイルを動かす前に、echo で予定だけ表示して確かめる

ここまでで、スクリプトを作って動かせるようになりました。次の記事では、動いているプログラム(プロセス)を見たり止めたりする方法を学びます。スクリプトが止まらなくなったときにも役立ちます。


次に読む記事


関連する記事