スクリプトを書く

INPUT · スライド

引数を受け取る(`$1`)

01 / 08

相手を選べないと不便

前の回で作ったスクリプトは、いつも同じことしかしなかったね。

#!/bin/shwc -l aka.txt

これは aka.txt しか数えられないでしょう。他のファイルを数えたければ、書きかえるしかないね。

でもあなたが毎日打っているコマンドは、そうなっていないよ。

wc -l aka.txtwc -l ao.txt

うしろに書いた相手を数えてくれるでしょう。この形にしたいんだ。

~ $ ./kazoe.sh aka.txt3~ $ ./kazoe.sh ao.txt2

うしろに書く言葉を引数と呼ぶよ。今日はこれを受け取る方法をやるね。

これができると、スクリプトが道具になるんだ。

手順を固めたもの   1つのことしかできない引数を取れるもの   同じ手順を、いろいろな相手に使える

1つ覚えるだけで、使える場面が何倍にもなるでしょう。

02 / 08

$1 で1つめを受け取る

うしろに書いた言葉は、番号で取り出せるよ。

#!/bin/shecho ichi=$1echo ni=$2

動かしてみるね。

~ $ ./a.sh aa bbichi=aani=bb

書いた順に番号が付くんだ。

./a.sh aa bb       │  └ $2       └─── $1

変数と同じ形で使えるでしょう。$ を付けて呼ぶところまで同じだね。

書いていない番号は空になるよ。

~ $ ./a.sh aaichi=aani=

エラーにはならず、ただ空なんだ。ここは気をつけるところだよ。あとで対策をやるね。

そして書くときの注意が1つあるよ。

echo 'echo ichi=$1' >> a.sh     ○ シングルで囲むecho "echo ichi=$1" >> a.sh     × いま広がって空になる

章10でやった引用符だね。$1スクリプトが動くときに広がってほしいので、書くときは広げさせないんだ。

03 / 08

$#$@$0

番号のほかに、便利なものが3つあるよ。

#!/bin/shecho kazu=$#echo zenbu=$@echo namae=$0

動かすとこうなるね。

~ $ ./b.sh x y zkazu=3zenbu=x y znamae=./b.sh
書き方意味
$#引数の個数
$@引数の全部
$0呼ばれたときの名前

$# は使い道がすぐ分かるでしょう。

引数が0個なら、使い方を教えて終わる

$@ は「もらったものを、そのまま別のコマンドに渡す」ときに使うよ。

#!/bin/shwc -l "$@"        もらったファイル全部を数える

$0 は使い方を出すときに便利だね。

echo "tsukaikata: $0 fairu"

名前を書きかえても、メッセージが勝手に付いてくるでしょう。ファイル名を変えても直さなくていいんだ。

もう1つだけ注意があるよ。10個めからは形が変わるんだ。

$10     → 「$1 のうしろに 0」と読まれる${10}   → 10 個めになる

迷ったら { } で囲むといいよ。

04 / 08

"$@" は囲んで使う

ここは大事なところだよ。空白の入った名前を渡してみるね。

#!/bin/shfor A in $@; do echo [$A]; done

動かすとこうなるよ。

~ $ ./d.sh "aru mono" hoka[aru][mono][hoka]

割れてしまったね。囲んで渡したのに、2つになったでしょう。

囲むと直るよ。

for A in "$@"; do echo [$A]; done
~ $ ./c.sh "aru mono" hoka[aru mono][hoka]

理由は章10でやったことだね。

$@ を広げる  →  aru mono hoka空白で割る   →  aru / mono / hoka

広げたあとに割られるんだった。だから囲んで止めるんだ。

"$@" は特別で、引数の切れ目を覚えたまま広がるよ。

"$@"    →  "aru mono" "hoka"  (切れ目が残る)$@      →  aru mono hoka      (切れ目が消える)

よく似た $* もあるけれど、こちらは切れ目が消えるほうだよ。

> 引数を渡すときは、いつも "$@"

これだけ覚えておけば大丈夫だね。理由も説明できるでしょう。

05 / 08

省略されたときの備え

引数を書き忘れる人がいるよ。自分も忘れるね。

~ $ ./kazoe.sh(何も指定されず、変なことが起きる)

備え方は2つあるよ。

1. 既定の値を決める

#!/bin/shecho [${1:-kirei}]
~ $ ./e.sh[kirei]        ← 省略したら既定~ $ ./e.sh yubi[yubi]         ← 書いたらそちら

章10の1本目でやった ${VAR:-既定} と同じ形だね。番号でも使えるんだ。

2. 無ければ断る

#!/bin/sh[ $# -eq 0 ] && echo "fairu wo kaite ne" && exit 1wc -l "$1"

[ $# -eq 0 ] は「個数が 0 と等しいか」だよ。-eq は equal(等しい)の略だね。

~ $ ./g.shfairu wo kaite ne~ $ echo $?1

使い方を教えて、失敗として終わるでしょう。これがちゃんとした道具の作りだよ。

exit 1 は「失敗で終わる」という意味だよ。数字の意味は、あとの回でくわしくやるね。

06 / 08

shift で順に送る

もう1つ道具を渡しておくね。

#!/bin/shshiftecho [$1]
~ $ ./f.sh aa bb[bb]

$1 なのに 2つめが出たでしょう。shift引数を1つずつ前へ送るんだ。

最初:        $1=aa  $2=bbshift の後:  $1=bb

何に使うかというと、こういう形だよ。

#!/bin/shBASHO=$1shiftwc -l "$@"        残り全部を数える

1つめだけ別に扱って、残りをまとめて渡すでしょう。あなたが打っているコマンドと同じ形になったね。

grep kotoba fairu1 fairu2     └ 1つめ  └── 残り

grep の中でも、たぶん似たことをしているんだ。

shift は繰り返しと組み合わせても使えるよ。

while [ $# -gt 0 ]; do  echo [$1]  shiftdone

1つずつ取り出して、無くなるまで回すという形だね。これは while の回でやるよ。今日は「送る道具がある」ことだけ覚えておいてね。

07 / 08

書くときの引用符

この回でいちばん引っかかるのが、ここだよ。

スクリプトに $1 と書きたいのに、こう打つと消えてしまうんだ。

~ $ echo "wc -l $1" >> a.sh~ $ cat a.shwc -l                  ← $1 が消えた!

いま打っているシェルが $1 を広げてしまったんだね。あなたが打っている端末には引数が無いので、空になったんだ。

シングルで囲むと直るよ。

~ $ echo 'wc -l "$1"' >> a.sh~ $ cat a.shwc -l "$1"             ← そのまま入った

章10でやった表を思い出してね。

シングル  何も広げない   →  そのままファイルに入るダブル    $ を広げる     →  いま広がってしまう

書きたい文字をそのまま残したいときはシングルでしょう。.profile$PATH を書いたときと、まったく同じ話だね。

そして中で "$1" と囲むのも忘れないでね。

echo 'wc -l "$1"' >> a.sh            ↑ 中はダブルで囲む

外はシングル、中はダブル。囲みが二重になるけれど、役目が違うんだ。

外側  いま広げさせない内側  動くときに空白で割られない

08 / 08

さあ、打ってみよう

この回で使う形をまとめておくね。

$1 $2      1つめ・2つめ${10}      10 個め$#         個数"$@"       全部(切れ目を残す)$0         呼ばれた名前${1:-既定}  省略されたときの値shift      1つずつ前へ送る

書くときの作法はこれだよ。

echo 'wc -l "$1"' >> a.sh     ↑ 外はシングル

そして今日の結論を書いておくね。

> 引数を取れると、スクリプトは道具になる

前の回のものは「手順の記録」だったけれど、今日からは lswc と同じ形のものが作れるんだ。

./kazoe.sh aka.txt      あなたが作った道具wc -l aka.txt           誰かが作った道具

呼び方が同じでしょう。区別が無くなってきたね。

次の回からは、中身を賢くしていくよ。

次: if で条件で分ける  → ファイルが無ければ教える

今日やった [ $# -eq 0 ] が、その入口になるよ。では作ってみよう。