シェルスクリプト覚え書きその2 制御構造編

条件分岐

  • if文
    例:ひとつ目の引数が1ならYES,そうでないならNOと出力
#!/bin/bash

if [ "$1" = "1" ] ;then # [,],=の前後にスペースが必要  
    echo "YES"
else
    echo "NO"
fi

比較

  • 文字列の比較
    str1 = str2 str1とstr2が等しい
    str1 != str2 str1とstr2が等しくない
    -n str1 str1が空
    -z str1 str1は空ではない

  • 整数の比較
    int1 -eq int2 int1 == int2
    int1 -ne int2 int1 != int2
    int1 -lt int2 int1 < int2
    int1 -le int2 int1 <= int2
    int1 -gt int2 int1 > int2
    int1 -ge int2 int1 >= int2

例:2つの引数のうち小さい方を表示する

if [ "$1" -le "$2" ];then
    echo $1
else
    echo $2
fi
  • case文
    <文字列>が<パターン>に一致する場合に処理を実行して抜ける
case <文字列> in 
    <パターン1>)
        処理
        ;;
    <パターン2>)
        処理
        ;;
esac

繰り返し

  • for文
    for文を用いるとリストの各要素について順番に処理を行うことが出来る
for <変数名> in <リスト>
do
    繰り返す部分
    ここではリストの各要素が変数名で参照できる
done  

例 001.txtから005.txtまでの5つのファイルを作成*1

#!/bin/bash

for n in $(seq 1 5)
do
    touch "00$n.txt"
done
  • while文
    <条件>が真である(終了ステータスが0である)間は繰り返し処理を行う
while <条件(コマンド)>
do
    繰り返し処理
done

例:無限ループ
一秒ごとにhogeと言う

#!/bin/bash

while :
do
  echo hoge
  sleep 1
done

*1:実際にはブレース展開のほうが便利 katorinax.hatenablog.com

シェルスクリプト覚え書き シェル変数と引数 編

変数関連

  • 変数の定義

file=/media/usr-name/
変数名に使えるのは アルファベット、数字、アンダースコアのみ

  • 変数の参照

変数の値を参照する際には、変数名の前に$をつける。

echo $file  
/media/user-name/

コマンド置換

コマンド置換を利用することで、コマンドの吐いた標準出力を文字列として取得することが出来る。
コマンド置換:$(<コマンド名>)
例 シェル変数filenameに、現在時刻を代入する

$ filename=$(date|tr ' ' '_')
$ echo $filename
Mon_Apr__3_14:30:20_JST_2017

コマンドライン引数を用いる

位置パラメータというシェル変数を用いることで、シェルスクリプトコマンドライン引数を導入できる

  • 位置パラメータ
    $ ./hoge.sh aaa bbb と引数付きでシェルスクリプトを実行した際、
    “./hoge.sh"は$0 "aaa"は$1 "bbb"は$2というシェル変数に格納される
    引数の個数(この場合は2つ)は$#、引数全体(この場合はaaa bbb)は$@というシェル変数に格納される # 具体例
    位置パラメータを表示するシェルスクリプト param.sh
#!/bin/bash
echo $0
echo $1
echo $2
echo $3
echo $#
echo $@

実行

$ sudo chmod +x param.sh
$ param.sh aaa bbb  
./param.sh # $0
aaa        # $1
bbb        # $2
           # $3(無い)
2          # $#(引数の数)
aaa bbb    # $@(すべての引数)

シェルスクリプトをどこからでも実行できるようにする

通常シェルスクリプトは、シェルスクリプトが存在しているディレクトリで$ ./hoge.shとタイプすることで実行する
これを、どのディレクトリからでも、シェルの名前だけで実行できるように設定する

  1. シェルスクリプトを保存しておくディレクトリを作成
    $ mkdir ~/bin
  2. サーチパスに~/binを追加
    $ PATH="$PATH:~/bin"
  3. スクリプトに実行権限を追加
    $ sudo chmod +x hoge.sh

ディレクトリ ~/bin にシェルスクリプトを配置すれば、スクリプトの名前をタイプするだけで$ hoge.shで実行できるようになった

sedの使い方

sed はストリームエディタの略
vimEmacs,メモ帳と言った対話型エディタとは異なり、ストリームエディタはファイルを加工して結果を標準出力に書き出す。
-i オプションで上書きする。


  • 行を指定して削除
    $ sed <数字>d ファイル名 でファイルの<数字>行目を削除できる
    例1:1行目を削除 $ sed 1d hoge.txt
    例2:3から10行目を削除 $ sed 3,10d hoge.txt
    正規表現を指定に用いることも出来る。
    この場合、正規表現をスラッシュで囲む。
    例3:先頭がAで始まる行を削除 $ sed /^A/d hoge.txt

  • 行を指定して表示
    $ sed -n <数字>p ファイル名 でファイルの<数字>行だけを出力できる

  • 文字列を指定して置換
    $ sed s/<置換前>/<置換後>/フラグ ファイル名 でファイルの<置換前>文字列を<置換後>文字列に変換できる
    置換前文字列には正規表現を用いることが出来る
    フラグにはgを指定すると見つかったすべての文字列を置換できる

grepの拡張正規表現

grepコマンドの-Eオプションを利用することで、拡張正規表現を用いることが出来る


  • 1回以上の繰り返し
    ‘+'で直前の文字の一回以上の繰り返しを意味する
    grep -E 'Be+r' = Ber,Beer,Beeeer …

  • 0回または1回の繰り返し
    ‘?'は直前の文字の0または1回の繰り返しを意味する
    grep -E 'Be?r' = Br or Ber

  • 特定回数の繰り返し
    {m,n}でm回以上n回以下の繰り返しを意味する
    {n}はちょうどn回の繰り返しを意味する
    {n,}はn回以上の繰り返しを意味する
    例:10桁の数字を抽出
    grep -E '[0-9]{10}'

  • 正規表現をグループ化する
    ()で囲うとその単語をグループ化出来る
    (abc|def)でabc または defにマッチする文字列を検索できる

grepやvimで使える正規表現

$ grep [オプション] <検索パタン> <ファイル名>で、ファイルからパタンに一致する内容がある行を抽出
例: /etc ディレクトリから'cron'に一致する内容を抽出

$ ls /etc | grep cron
anacrontab
cron.d
cron.daily
cron.hourly
cron.monthly
crontab
cron.weekly

正規表現まとめ

  • 任意の一文字にマッチ
    ‘.’(ドット) で任意の一文字にマッチングする
    ‘.'自体を検索したい場合は’\.‘を用いる
    例:/etc 内にある ’.conf'ファイルを検索
$ ls /etc | grep '\.conf'
adduser.conf
apg.conf
appstream.conf
brltty.conf
ca-certificates.conf
debconf.conf

  • 特定の一文字にマッチ
    []で囲った中に文字を入れると、その中いずれか一文字に一致するものを検索する。
    例えば kato と sato を同時に検索したければ
    [ks]ato になる。
    [a-z]でa,b,c…zのいずれか一文字
    [^ ]で [ ] の中に含まれない一文字

  • 行頭・行末でマッチ
    ‘^'で行頭、’$‘で行末にあるパタンを検索できる
    例:ホームディレクトリにある隠しファイル(行頭が’.‘)を抽出
$ ls ~ | grep '^\.'
.
..
.adobe
.bash_history
.bash_logout
.bashrc
.cache

grep ^$ で空行を抽出


  • 繰り返しをマッチ
    ‘*'で前の文字の任意回の繰り返しを意味する
    例:Be*r = Ber,Beer,Beeeeer,Beeeeeeeeeeeeeeeer…
    .* はあらゆる文字列にマッチする

便利なフィルタコマンド覚え書き

  • head
    標準入力の先頭数行を表示
    -n <数字> : 指定した行数を出力

  • tail
    標準入力の末尾数行を出力
    -n <数字> : 指定した行数を出力
    -f <ファイル名> : 指定したファイルにリダイレクトで追記(>>)があるとリアルタイムで表示

  • grep
    指定した検索パタンに一致する行を出力
    -n:行番号付きで結果を出力
    -i:大文字・小文字を区別せずに検索
    -v:一致しなかった行を出力
    -o:一致した部分のみを表示

  • sort
    入力をアルファベット順に並び替える
    -n:数字順に並び替える
    -k <数字>:<数字>番目のフィールドをソートに用いる
    -r:逆順にソート

  • tac
    入力を逆順に出力する

  • wc
    行数・単語数・バイト数を出力する
    -l:行数のみ出力
    -w:単語数のみ出力
    -c:バイト数のみ出力

  • uniq
    入力から、隣り合った重複する行を取り除いて出力
    -c:重複がいくつあるか数えて表示

  • cut -d <区切り文字> -f <フィールド番号> <ファイル名>
    <区切り文字>で指定した文字で入力を分割し、<フィールド番号>で指定したフィールドの内容だけを出力
    環境変数 $PATH のうち10個目を表示
$ echo $PATH | cut -d : -f 10  
/usr/local/games

  • tr<文字(置換元)> <文字(置換先)>
    入力の特定の文字を置き換える
    例 入力をすべて大文字にする$ tr a-z A-Z
    例2 アルファベットをすべて伏せ字にする
$ ls | tr A-z '*'
*******
*********
*********
*******
********.*******
******

-d <文字> : 指定した文字を削除


  • diff <比較元> <比較先>
    ファイルの差分を表示
    差分がない場合は何も表示しない