みーのぺーじ

みーが趣味でやっているPCやソフトウェアについて.Python, Javascript, Processing, Unityなど.

シェルスクリプト まとめ

シェルスクリプトはなんとなく書けるけど,なんとなくしか書けないので,改めて自分用にシェルスクリプトをまとめました.$ から始まる行を実行し,結果を次の行で示します.概ねThe Shell Scripting Tutorialを参考にしています.

実行環境

$ cat /etc/issue
Ubuntu 20.04.1 LTS
$  bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu) ...

Hello World!

1個目が命令で,それ以降は引数として解釈される.改行により区別される.

$ echo "Hello World!"
Hello World!
$ echo "Hello"  "World!"
Hello World!
$ echo Hello World!
Hello World!

変数

"=" で変数に代入する."="の前後にスペースを入れてはいけない.$から始めると変数を参照する.

$ MESSAGE="Hello World!"
$ echo $MESSAGE
Hello World!

" で囲むと文字列になるが,その中で$から始めた部分は変数に置き換わる.

$ NAME=John
$ echo "He is $NAME."
He is John.

変数は初期化されずに参照すると空になる.エラーは発生しない.

$ echo "VAR is $VAR"
VAR is
$ VAR=John
$ echo "VAR is $VAR"
VAR is John

"_"などを使う名前の変数を扱うには{}で囲む.$VAR_1_1ではどこまでが変数の名前か曖昧なので,${VAR_1}_1と書く.

$ VAR_1=John
$ echo "VAR_1 is ${VAR_1}_1"
VAR_1 is John_1

エスケープ文字

一部の記号には特殊な意味がある.スペースは区切りの意味になるので," で囲む."を表示したいときは\を前に付ける.

$ echo Hello           World
Hello World
$ echo "Hello      World!"
Hello      World!
$ echo "Hello \"World\""
Hello "World"

* はカレントディレクトリのファイル全てを示す.*vは最後がvで終わる全てのファイルを示す.

$ echo *
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
$ echo *v
dev srv

{ }でコンマ区切りの文字列を囲むと,展開される.複数あれば順列となる.

$ rm *
$ ls
$ touch {1,2,3,4}.sh
$ ls
1.sh  2.sh  3.sh  4.sh
$ rm *
$ ls
$ touch {a,b,c,d,e}.{txt,csv,html}
$ ls
a.csv  a.html  a.txt  b.csv  b.html  b.txt  c.csv  c.html  c.txt  d.csv  d.html  d.txt  e.csv  e.html  e.txt

ループ

for in でリストに対してループする.

$ cat 1.sh
for i in 1 2 3 4 5 6 seven 8 nine
do
  echo "i=$i"
done
$ sh 1.sh
i=1
i=2
i=3
i=4
i=5
i=6
i=seven
i=8
i=nine

while : で無限ループする.:はtrueと評価される.

$ cat 2.sh
while :
do
  echo "Type something in (^C to quit)"
  read INPUT_STRING
  echo "You typed: ${INPUT_STRING}"
done
$ sh 2.sh
Type something in (^C to quit)
Test1
You typed: Test1
Type something in (^C to quit)
Test2
You typed: Test2
Type something in (^C to quit)
This is a sample message.
You typed: This is a sample message.
Type something in (^C to quit)
^C

テスト

[testという名前の命令である.

$ type [
[ is a shell builtin
$ which [
/usr/bin/[
$ ls -l /usr/bin/test
-rwxr-xr-x 1 root root 55640 Sep  5  2019 /usr/bin/test
$ ls -l /usr/bin/[
-rwxr-xr-x 1 root root 59736 Sep  5  2019 '/usr/bin/['

命令なので,lsと同様,間にスペースが必須である.[$VAR = 0 ]はエラーとなる.&& を使って簡単な判断ができる.等しいことを比較するために,=を使う.==でも構わないが一般的ではない.

$ VAR=0
$ [ $VAR = 0 ] && echo zero
zero
$ VAR=1
$ [ $VAR = 0 ] && echo zero
$ [$VAR = 0 ] && echo zero
bash: [1: command not found

if...then...else...の構文で条件分岐ができる.ifthenの間には改行が必要だが,";"を置いて改行の代わりとすることもできる.

$ cat 3.sh
VAR=4
if [ $VAR -lt 0 ];then
  echo "VAR < 0"
else
  echo "VAR >= 0"
fi
$ sh 3.sh
VAR >= 0

testコマンドにはオプションが多数あり,ファイルの存在を確認したりする(-e)ことも可能である.

test man page

-z で文字列が空ならばtrueとなり,-nで文字列が空でなければtrueとなる.これを利用して,RETURNを入力するまでループすることができる.

$ cat 4.sh
VAR=0
while [ -n "$VAR" ]
do
  echo "Enter some text. (RETURN to quit)"
  read VAR
  if [ -n "$VAR" ]; then
    echo "You said: $VAR"
  fi
done
$ sh 4.sh
Enter some text. (RETURN to quit)
Test1
You said: Test1
Enter some text. (RETURN to quit)
Test2
You said: Test2
Enter some text. (RETURN to quit)
This is a sample message.
You said: This is a sample message.
Enter some text. (RETURN to quit)

特別な変数

$0は,起動されたスクリプト名である.

$ cat 5.sh 
echo $0
$ sh 5.sh 
5.sh

$1は1個目の引数を示し,同様に$2, $3, ... が存在する.$@はスクリプト名を除いた引数全てを示す.

$ cat 6.sh 
echo "\$1=$1"
echo "\$2=$2"
echo "\$3=$@"
$ sh 6.sh      
$1=
$2=
$3=
$ sh 6.sh 1 two                 
$1=1
$2=two
$3=1 two

$$は実行するプロセスのPIDを示す.

$ echo $$
1

デフォルト値

:-は,変数の値がなければ直後の値を返す.変数は変わらない

$ VAR=1
$ echo "VAR = ${VAR:-2}, $VAR."
VAR = 1, 1.
$ VAR=0
$ echo "VAR = ${VAR:-2}, $VAR."
VAR = 0, 0.
$ VAR=
$ echo "VAR = ${VAR:-2}, $VAR."
VAR = 2, .

:=は,変数の値がなければ直後の値を代入する

$ VAR=1
$ echo "VAR = ${VAR:=2}, $VAR."
VAR = 1, 1.
$ VAR=0
$ echo "VAR = ${VAR:=2}, $VAR."
VAR = 0, 0.
$ VAR=2    
$ echo "VAR = ${VAR:=2}, $VAR."
VAR = 2, 2.

Unixコマンド

"`" (バッククォート)で囲むと,コマンドとして実行される.入力に応じたコマンドを実行できるようになる.

$ touch {a,b,c,d,e}.{txt,csv,html}
$ ls
7.sh  a.csv  a.html  a.txt  b.csv  b.html  b.txt  c.csv  c.html  c.txt  d.csv  d.html  d.txt  e.csv  e.html  e.txt
$ cat 7.sh
FILES=`ls *.$1`
echo $FILES
$ sh 7.sh txt
a.txt b.txt c.txt d.txt e.txt
$ sh 7.sh html
a.html b.html c.html d.html e.html
$ sh 7.sh csv 
a.csv b.csv c.csv d.csv e.csv

{ }で囲んだ部分は同じプロセスで実行される.( )で囲んだ部分はサブシェルで実行される.カレントディレクトリを一時的に変更したい時に便利.

$ cat 8.sh 
echo `pwd`
{
  cd /usr
  echo `pwd`
}
echo `pwd`
(
  cd /home
  echo `pwd`
)
echo `pwd`
$ sh 8.sh 
/home
/usr
/usr
/home
/usr

よく使うコマンド

文字列の置換と削除

trコマンドを使う.translateの略で,文字列の置換と削除ができる.範囲が指定できるので,全て大文字/小文字に置換することもできる.

$ echo Hello | tr e E
HEllo
$  echo Hello | tr a-z A-Z
HELLO

-dで削除する.改行を削除するのに便利.

$ tr --version
tr (GNU coreutils) 8.30
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Jim Meyering.
$ tr --version | tr -d '\n'
tr (GNU coreutils) 8.30Copyright (C) 2018 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.Written by Jim Meyering.

気をつけること

スコープは存在しないので,実行される順番に従って処理される.