shの覚書

 
tiutiu.net/ プログラム/language/sh/
2007/4/25
変数
#!/bin/sh
foo=5 #ここで$はいらない
echo $foo

=の両端に空白は許されない

環境変数も$をつけることで出力される。

#!/bin/sh
echo $HOME

tcshの場合,

#!/bin/tcsh
set foo = 5
echo $foo

あるいは

#!/bin/tcsh
set foo = 5;echo $foo

bashの場合,

#!/bin/bash
foo=5       # 代入時に空白は許されないらしい。 
echo $foo

あるいは

#!/bin/bash
foo=5;echo $foo
他コマンドの実行

次のようにバッククォート"`"を使用することで, 各実行コマンドの出力を変数に代入できる。

foo=`echo test | sed 's/est/ree/g'`
bar=`echo test | cut -c1-3` # substrの代わりになる
hoge=`wc test | wc -c`
条件分岐

sh, bashの場合

#!/bin/sh
if [ "$1" = "morning" ]; then
  echo "Good morning"
elif [ "$1" = "afternoon" ]; then
  echo "Hello!"
else
  echo "Good evening";
fi

$1はコンソールからの第一引数。

=のほかに!=も使える。否定の場合は次の書式でもよい。

if [ ! "$1" = "morning" ]; then

"["はtestと同じである。

if test "$1" = "morning"; then

複数の条件を扱いたいならば, かつ"-a"とあるいは"-o"を使用する。

#!/bin/sh

foo=1
bar=1

if [ $foo = 1 -a $bar = 1 ]; then
   echo 1
else
   echo 2
fi

ファイルの存在のチェックなど特殊なオプションがある。

#!/bin/sh
if [ -f "foo" ]; then
    echo "foo is exist."
else
    echo "foo is not exist."
fi
オプション意味
-fファイルの存在
-dディレクトリの存在
-z対象が空の文字列ならtrue
-n対象が空の文字列でないならtrue
[, testの代表的なオプションと意味

tcshの場合

#!/bin/tcsh
set foo = 1
if ( $foo == 1 ) then
  echo 1
else
  echo 2
endif  # endifを endif; としてはいけないらしい。
最後のコマンドの実行状態

コマンドが成功して終わったかどうかをみることができる 特別な変数$?が存在する。

$ test "a" = "b"
$ echo $?
1
$ test "a" = "a"
$ echo $?
0
$
反復

コマンドラインから直接行う場合

$ for f in *.{txt,html}
> do
> echo $f
> done

そのディレクトリの拡張子がtxtとhtmlのファイルの一覧が出力される。

ファイルにしたためる場合

#!/bin/bash

for f in *.{html,txt}
do
  echo $f
done

doの位置をforと同じ行にするなら

#!/bin/bash

for f in *.{html,txt}; do
  echo $f
done

forのinには, 空白で区切れば, いくらでも入れることができる。

#!/bin/bash

for i in 1 2 3 4 5 6 7 8 9 do
  echo $i
done

実行結果は, 1から9までが表示される。これを使えば, 最初の例は 次のようにも書ける。

#!/bin/sh

for i in *.html *.txt; do
  echo $i
done

whileを使う場合は次のとおり。

#!/bin/sh

i=0
while [ $i -lt 10 ]; do   ### [ ] の前後には空白を入れるように! 
   echo $i
   i=`expr $i + 1`        ### iの値を一つ増やす
done;

-ltは"未満"。"以下"は-le。

標準入力からの読み取り

ある実行の結果を行ごとに変数に入れて利用したいと きなどに, readを使用する。

#!/bin/sh
# すべてのphpファイル中の2006を2007に変更する。

find . -name '*.php' -print | while read php; do
    sed -i 's/2006/2007/' $php
done;

なお, この場合while句のブロックの変数は終了後に保存されないことに注意。 たとえば, ディレクトリの一覧を後で使いたいと思い, 次のような コードを書いたとする。

#!/bin/sh

dirlist=""
find . -maxdepth 1 -type d -print | while read d; do
    dirlist="$dirlist $d"
done;
echo $dirlist

最後のecho $dirlistでは何も表示されない。dirlist="$dirlist $d"の 直後に$dirlistをechoしたならばディレクトリのリストが表示される。 なぜなら, パイプを用いているためwhileはforkされた子プロセスで 実行されているからである。このようにするとパイプで標準入出力を変更する 実装が自然に行える。なお, 上記の目的を実現したい場合は次のとおり。

#!/bin/sh

dirlista=`find . -maxdepth 1 -type d -print`
dirlist=""
for d in $dirlista; do
    if test "$d" != "."; then
        dirlist="$dirlist $d"
    fi
done;
echo $dirlist
echo $dirlista

$dirlistaだけでも空白区切りのディレクトリ名一覧ができるので, 例としてふさわしいようにカレントディレクトリ(.)を抜いている。

コマンドラインからの引数

$@は引数全てを空白区切りで渡す。$1は最初の引数, $2は2番目の引数... 以下$9まで。$0はスクリプト名。

#!/bin/bash

echo $@
echo $1
echo $2
echo $3
echo $0
関数
#!/bin/bash

foo()
{
    echo $1
}

foo bbb

関数は使用する前に定義しておく必要がある。関数定義中の$1は関数の第一引数。 コンソールからの第一引数とは区別される。


Google