Open11

ShellScript学習メモ

MasaHeroMasaHero

0628

教材:新しいShellScriptの教科書 14章

noexecオプション

set -o noexec set -n で実行せずに構文チェックする。

shellcheck(静的解析)

sudo apt install shellcheck

$ shellcheck filename.sh

Bats 動的テスト

https://github.com/sstephenson/bats
sudo apt install bats

構文

@test TestDescription{
    testcode1
    testcode2
}

試験運用

@test 'addiction using arithmetic expansion' {
    value=$(( 5 + 3 ))
    [[ $value -eq 8 ]]
}

@test 'addiction negative value using arithmetic expansion' {
    value=$(( 5 + -7 ))
    [[ $value -eq -2 ]]
}

bash option

set -o 1文字オプション 内容
verbose -v 実行前にコマンドラインを表示する
xtrace -x コマンドラインの内容を出力しながら実行する
nounset -u 未定義変数があった場合エラーとする
errexit -e コマンドの終了ステータスが0以外が出たら、即終了
MasaHeroMasaHero

0628 -2

関数

funcA(){
   echo $0
   COMMAND1
   COMMAND2
   return 0
}

funcA "hoge"

MasaHeroMasaHero

制御構造

if

templete 1

if condition; then
      # process
fi

templete 2

if condition; then
      # process1
elif condition; then
      # process2
else
      # process3
fi

test , [] コマンド

echo "[] command"
[ "$answer" = "yes" ]
echo $?

echo "test command"
test "$answer" = "yes"
echo $?

if文で何も処理しない場合

  if [ "$1" = yes ]; then
      :
      # 何も処理をせず、exit code 0を返す
  else
      echo NO
  fi
MasaHeroMasaHero

制御構造 2

&& ||

&&

command1 && command2
command1が終了コードが0のときのみ、command2を実行する

||

command1 || command2
command1が終了コードが0以外のときのみ、command2を実行する

[[]]

[との違いは、&&,|| が条件文内で使えること

  #!/bin/bash

  str1=xxx
  str2=yyy

  if [[ $str1 = "$str2" ]]; then
      echo YES
  else
      echo NO
  fi

パターンマッチング

#!/bin/bash

echo "pattern matching1"
str1=xyz
if [[ $str1 = x* ]]; then
    echo "MATCHED"
else
    echo "NOT MATCHED"
fi

echo "pattern matching2"
pattern='x*'
  if [[ $str1 == $pattern ]]; then
    echo "MATCHED"
else
    echo "NOT MATCHED"
fi

注意点

  • [[]] コマンドは bashの組み込みコマンドなので、$SHELLがbashでない場合は注意すること。
    (それで10分ほど躓いた)
$ echo $SHELL
/bin/sh
$ sh test.sh
test.sh: 6: [[: not found
  • 変数を"でクォートしてるかに関わらず、変数の値が一つの要素と見なされる
MasaHeroMasaHero

制御構造 3

for loop

templete

#!/bin/bash

# イテレータ
for i in aaa bbb ccc
do
    echo $i
done

# 引数ループ
for i in "$@"
do
    echo $i
done

# カレントディレクトリの`*.txt`
for i in *.txt
do
    echo $i
done

continue , break

  #!/bin/bash

  for i in {1..9}
  do
      if [[ $i -eq 3 ]]; then
          echo "$i continue"
          continue
      elif [[ $i -eq 5  ]]; then
          echo "$i break"
          break
      fi

      echo $i
  done

MasaHeroMasaHero

制御構造 4

case文

#!/bin/bash

file="$1"
  case "$file" in
      *.txt)
          echo "*.txt"
          head "$file"
          ;;
      *.sh)
          echo "*.sh"
          head "$file"
          ;;
      *)
          echo "*"
          head "$file"
          ;;
  esac

while, until

  #!/bin/bash
  echo "while"
  i=0
  while [[ $i -lt 10 ]]
  do
      echo "$i"
      i=$(( i + 3 ))
  done

  echo "until"
  i=0
  until [[ $i -gt 10 ]]
  do
      echo "$i"
      i=$(( i + 3 ))
  done

while

conditionが真である限り、ループする

while condition
do
   process
done

until

conditionが偽である限り、ループする

until condition
do
   process
done
MasaHeroMasaHero

正規表現と文字列操作

10章

grep

$ grep [option] PATTERN FILE_NAME

拡張正規表現

自分の理解があやふやなものをメインにリストアップした。

文字に関するメタ文字

. : 何かしらの1文字
[]: カッコ内含まれる文字1文字
[0-9]:0~9のうちいずれか1文字
[a-z]:a~zのうちいずれか1文字
[0-9a-zA-Z]:0~9もしくはa~z/A~Zのいずれか1文字
[^]:カッコ内に含まれない1文字

位置に関するメタ文字

^:行頭
$:行末

繰り返しを指定するメタ文字

*:0回以上の繰り返し
+:1回以上の繰り返し
?:0~1回の繰り返し
{n}:N回の繰り返し
{m,n}:M回以上N回以下の繰り返し
{m.}:M回以上の繰り返し

MasaHeroMasaHero

grepコマンドの詳細

-Eを指定しない、grepは基本正規表現である。

masahero@/home/masahero/Practice/shellScripting/lesson_0719 %
$ cat example.txt
───────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: example.txt
       │ Size: 138 B
───────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ /test1/file_1
   2   │ /test1/file_2
   3   │ /test2/file_1
   4   │ /test3/file_x
   5   │ /test4/file_y
   6   │ /test10/file_1
   7   │ /test11/file_1
   8   │ /work/test1/file_x
   9   │ /work/test5/file_1
───────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
masahero@/home/masahero/Practice/shellScripting/lesson_0719 %
$ grep 'test1|test2' example.txt
masahero@/home/masahero/Practice/shellScripting/lesson_0719 %
$ grep -E 'test1|test2' example.txt
/test1/file_1
/test1/file_2
/test2/file_1
/test10/file_1
/test11/file_1
/work/test1/file_x
masahero@/home/masahero/Practice/shellScripting/lesson_0719 %
$
MasaHeroMasaHero

grepコマンドのオプション

-E:拡張正規表現を適用
-i:大文字小文字を区別しない
-e:複数パターンを適用する
-v:検索結果反転。パターンに当てはまらないものを出力する

masahero@/home/masahero/Practice/shellScripting/lesson_0719 %
$ grep -v '[0-9]$' example.txt
/test3/file_x
/test4/file_y
/work/test1/file_x
masahero@/home/masahero/Practice/shellScripting/lesson_0719 %
$
MasaHeroMasaHero

sed

$ sed [options] Script FILE_NAME

Scriptは、アドレスとコマンドで構成されている。

  • アドレスは検索範囲(行)のこと。
  • コマンドはアドレスに一致した行に対する操作のこと。(sコマンド。s/を指す)

sコマンド

s/検索対象/置換後文字列/フラグ

  • g :パターン該当箇所全て(指定しない場合は、最初にヒットする箇所のみ)
  • i :大文字小文字を区別無視

options

  • -r 拡張正規表現を使用する(sedも基本正規表現がデフォ)
  • -e スクリプトを指定する(-e を繋げて 複数スクリプトを指定する)
  • -i ファイルを変更して保存する(上書き)
MasaHeroMasaHero
masahero@/home/masahero/Practice/shellScripting/lesson_0719 %
$ cat example.txt
───────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: example.txt
       │ Size: 138 B
───────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ /test1/file_1
   2   │ /test1/file_2
   3   │ /test2/file_1
   4   │ /test3/file_x
   5   │ /test4/file_y
   6   │ /test10/file_1
   7   │ /test11/file_1
   8   │ /work/test1/file_x
   9   │ /work/test5/file_1
───────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
masahero@/home/masahero/Practice/shellScripting/lesson_0719 %
$ sed -i "s|work|WORK|g" example.txt
masahero@/home/masahero/Practice/shellScripting/lesson_0719 %
$ cat example.txt
───────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: example.txt
       │ Size: 138 B
───────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ /test1/file_1
   2   │ /test1/file_2
   3   │ /test2/file_1
   4   │ /test3/file_x
   5   │ /test4/file_y
   6   │ /test10/file_1
   7   │ /test11/file_1
   8   │ /WORK/test1/file_x
   9   │ /WORK/test5/file_1
───────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
masahero@/home/masahero/Practice/shellScripting/lesson_0719 %
$ sed -i "s|work|walk|gi" example.txt
masahero@/home/masahero/Practice/shellScripting/lesson_0719 %
$ cat example.txt
───────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: example.txt
       │ Size: 138 B
───────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ /test1/file_1
   2   │ /test1/file_2
   3   │ /test2/file_1
   4   │ /test3/file_x
   5   │ /test4/file_y
   6   │ /test10/file_1
   7   │ /test11/file_1
   8   │ /walk/test1/file_x
   9   │ /walk/test5/file_1
───────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
masahero@/home/masahero/Practice/shellScripting/lesson_0719 %
$