ユーザ用ツール

サイト用ツール


shellscript

差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
次のリビジョン
前のリビジョン
shellscript [2020/04/01 05:48] nullponshellscript [2025/10/31 02:06] (現在) nullpon
行 1: 行 1:
 ====== ShellScript ====== ====== ShellScript ======
 +
 +===== bash =====
 +
 +シェルスクリプトはbashをターゲットに作成する。POSIX互換のシェルの方がポータビリティが高いが今時bashがない環境は少ない。
 +
 +<code>
 +#!/bin/bash -eu
 +
 +...
 +</code>
 +
 +そんなbashがない環境の代表がalpine。dockerでシェルスクリプトを起動するならalpineを避けてdebianやubuntuをベースにすると良い。
 +
 +===== シェルスクリプトの実行方法 =====
 +
 +  - ''source''コマンドまたは''.''(スクリプトで定義した関数や変数を読み込む場合)
 +  - ''bash'', ''zsh''コマンドなどの引数で実行(理由がなければ避ける)
 +  - 実行権限を付与して直接実行(普段はこれ)
 +
 +==== sourceコマンドまたは. ====
 +
 +ファイル内に定義されているシェル関数や変数をシェルにロードする目的で使用する
 +
 +<code sh>
 +HOGE='1'
 +
 +p() {
 +  echo "$HOGE"
 +}
 +
 +
 +</code>
 +
 +これを実行すると、スクリプト終了後もpやHOGEがシェルに残る。
 +
 +<code sh>
 +$ source ./sample.sh
 +1
 +$ echo $HOGE
 +1
 +$ p
 +1
 +$ HOGE=2
 +$ p
 +2
 +</code>
 +
 +''source''や''.''は変数や関数定義の読み込みのために使うべきもので何らかの処理に使うのは不適切。pythonのvenvのactivateがこの方法でコマンドを作成している
 +
 +なお''.''について、bashでは以下いずれも動作するが、zshでは下は動作しない。''.''はファイルをフルパスまたは相対パスで与えるのが本来の記述でファイル名のみの指定で動作するのはbash固有の拡張。
 +
 +<code sh>
 +$ . ./hoge.sh
 +$ . hoge.sh 
 +</code>
 +
 +==== bash, zshの引数として実行 ====
 +
 +
 +意図がなければ基本的には避けるべき実行方法
 +
 +<code sh>
 +$ bash sample.sh 
 +</code>
 + 
 +UNIXスクリプトは実行するシェル・ランタイムをshbangで指定する。以下のスクリプトはzshを想定しておりbashでは正しく動作しない、またはエラーになる可能性がある
 +
 +<code sh>
 +#!/bin/zsh
 +
 +name="hello"
 +echo ${name:u}
 +</code>
 +
 +<code sh>
 +$ zsh hoge.sh
 +HELLO
 +$ bash hoge.sh
 +hello
 +</code>
 +
 +逆に自分がシェルスクリプトを書くときも何も考えず''#!/bin/bash''と書くのもよくない。bashを指定したらbashでは動作しない機能を使わないように注意が必要
 +
 +====  実行権限を付与して直接実行 ====
 +
 +普通はこれで実行する
 +
 +<code sh>
 +$ chmod +x sample.sh   # 一度のみで良い
 +$ ./sample.sh 
 +</code>
  
 ===== shの実行オプション ===== ===== shの実行オプション =====
行 6: 行 97:
   * -x 変数を展開した状態で実際に実行されるコマンドを標準エラー出力に書き出す   * -x 変数を展開した状態で実際に実行されるコマンドを標準エラー出力に書き出す
   * -u 未定義の変数があれば処理を打ち切る   * -u 未定義の変数があれば処理を打ち切る
 +  * -C noclobberオプションを有効にする(リダイレクトでファイルを上書きしようとするとエラーになる、追記はOK)
  
 shebangに追加されることが多い shebangに追加されることが多い
行 17: 行 109:
 ===== testコマンド ===== ===== testコマンド =====
  
-<code shellscript>+<code bash>
 test -f ./hoge.txt && echo "hoge.txtあるよ" test -f ./hoge.txt && echo "hoge.txtあるよ"
  
行 42: 行 134:
 ==== [[ ]] ==== ==== [[ ]] ====
  
-bashの拡張、bashならこちらを使った方がバグが少ないので+testコマンドbash拡張。単語分割やパス展開しないので、変数をクオートで囲む必要な
  
-単語分割やパス展開しないので、変数をクオートで囲む必要ない+<code bash> 
 +HOGE="a b c"
  
-<code sh> +[ $HOGE = "a b c" ] && echo "一致"  # => Error, bash: [: too many arguments
-$ HOGE="a b c" +
-[ $HOGE == "a b c" ] && echo "一致" +
-bash: [: too many arguments +
-$ [[ $HOGE == "a b c" ]] && echo "一致" +
-一致+
  
-$ HOGE=hoge.* +"$HOGE= "a b c" ] && echo "一致"  # => 一致 
-[ $HOGE == "hoge.*" ] && echo "一致" || echo "不一致" + 
-不一致 +[[ $HOGE = "a b c" ]] && echo "一致"  # => 一致
-[[ $HOGE == "hoge.*" ]] && echo "一致" || echo "不一致" +
-一致+
 </code> </code>
 +
 +<code bash>
 +HOGE="hoge.*"
 +
 +[ $HOGE = "hoge.*" ] && echo "一致" || echo "不一致"  # => 不一致
 +
 +[ "$HOGE" = "hoge.*" ] && echo "一致" || echo "不一致"  # => 一致
 +
 +[[ $HOGE = "hoge.*" ]] && echo "一致" || echo "不一致"  # =>一致
 +</code>
 +
 +zshでは ''['' も単語分割やパス展開しない拡張版に置き換えられている
  
 ===== read ===== ===== read =====
行 65: 行 163:
   read line   read line
   echo $line   echo $line
 +
 +プロンプトを出して入力を促す
 +
 +  echo -n "User Name: "
 +  read username
 +  echo $username
 +  
 +zshでは以下のようにかける
 +
 +  read "username?User Name: "
 +  echo $username
 +  
 +入力値をマスクしたい場合はread -s(決定時の改行も出力されなくなるのでechoを挟むとよい)
 +
 +  read -s "password?Password: "
 +  tty -s && echo
 +  echo $password | shasum -a 256
 +
 +
      
 標準入力が尽きるまで行を読み取る(Ctrl-DでEOFを送信) 標準入力が尽きるまで行を読み取る(Ctrl-DでEOFを送信)
行 93: 行 210:
 ==== シグナルのハンドリング ==== ==== シグナルのハンドリング ====
  
-<code>+<code bash>
 trap "echo trap sigint" INT trap "echo trap sigint" INT
  
行 105: 行 222:
 基本はシグナルのハンドリングだが、EXITとERRという疑似シグナルが利用できる。例えばmktempで作成した一時ファイルをスクリプト終了時に削除するなどの処理をEXITと組合わせて書ける。 基本はシグナルのハンドリングだが、EXITとERRという疑似シグナルが利用できる。例えばmktempで作成した一時ファイルをスクリプト終了時に削除するなどの処理をEXITと組合わせて書ける。
  
-<code>+<code bash>
 hoge=/tmp/hogehoge hoge=/tmp/hogehoge
 mktemp $hoge mktemp $hoge
行 144: 行 261:
 0-9A-Za-zのランダムな文字列を作成する。mac用 0-9A-Za-zのランダムな文字列を作成する。mac用
  
-<code> +<code bash
-cat /dev/random | base64 | fold -w 16 | egrep -v "[+/]" | head -n 1+cat /dev/random | base64 | fold -w 16 | egrep -v "[+/]" | head -n 1 
 +</code>
  
-head -c 100 /dev/random | base64 | tr -d "+/" | head -c 16+<code bash> 
 +head -c 100 /dev/random | base64 | tr -d "+/" | head -c 16
 </code> </code>
  
 セキュアな必要がないならば セキュアな必要がないならば
  
-<code> +<code bash
-shasum <(ls -al) | cut -d " " -f 1 +shasum <(ls -al) | cut -d " " -f 1 
 </code> </code>
  
行 159: 行 278:
 ===== 変数参照 ===== ===== 変数参照 =====
  
-<code>+<code bash>
 ${HOGE:-wang}   # HOGEに値がある場合はその値が展開される。HOGEが空の場合は、wangが展開される ${HOGE:-wang}   # HOGEに値がある場合はその値が展開される。HOGEが空の場合は、wangが展開される
 ${HOGE:+wang}   # HOGEに値がある場合はwangが展開される。HOGEが空の場合は何もしない ${HOGE:+wang}   # HOGEに値がある場合はwangが展開される。HOGEが空の場合は何もしない
行 166: 行 285:
 </code> </code>
  
 +===== シェル変数の加工 =====
 +
 +指定位置で切り取り
 +
 +<code bash>
 +x=abcdefg
 +echo ${x:1:4}      # => bcde
 +</code>
 +
 +変数の値の先頭・末尾でマッチした部分を削除する
 +
 +<code bash>
 +x=hogehogefugafuga
 +
 +echo ${x#hoge}       # => hogefugafuga 前方一致削除
 +
 +echo ${x%fuga}       # => hogehogefuga 後方一致削除
 +
 +echo ${x#h*e}      # => hogefugafuga * はワイルドカード
 +
 +echo ${x##h*e}     # => fugafuga ##はワイルドカードを前方最長一致にする
 +
 +echo ${x%f*a}        # => hogehogefuga * はワイルドカード
 +
 +echo ${x%%f*a}       # => hogehoge %%はワイルドカードを後方最長一致にする
 +</code>
 +
 +文字列置換
 +
 +<code bash>
 +echo ${var/hoge/HOGE}   # => HOGEhogefugafuga
 +
 +echo ${var//hoge/HOGE}  # => HOGEHOGEfugafuga グローバルマッチ
 +</code>
 +
 +
 +使用例:まとめてリネーム、拡張子まとめて変更
 +<code bash>
 +$ ls 
 +a.txt b.txt c.txt
 +
 +$ for i in `ls`; do mv $i ${i%.txt}.php; done
 +
 +$ls 
 +a.php b.php c.php
 +</code>
 ===== パラメータ展開 ===== ===== パラメータ展開 =====
  
  
-<code>+<code bash>
 HOGE="hoge.fuga.piyo" HOGE="hoge.fuga.piyo"
 echo ${HOGE#*.}          # 最短前方一致削除 => fuga.piyo echo ${HOGE#*.}          # 最短前方一致削除 => fuga.piyo
行 183: 行 348:
 コロンは何もしないビルトインコマンド コロンは何もしないビルトインコマンド
  
-<code>+<code bash>
 : hogehoge      # 何も起こらない : hogehoge      # 何も起こらない
 </code> </code>
行 189: 行 354:
 変数HOGEが空だった場合、nyanを代入する 変数HOGEが空だった場合、nyanを代入する
  
-<code>+<code bash>
 : ${HOGE:=nyan} : ${HOGE:=nyan}
 </code> </code>
行 195: 行 360:
 変数HOGEが空だった場合、Error HOGE is emptyと出力して終了 変数HOGEが空だった場合、Error HOGE is emptyと出力して終了
  
-<code>+<code bash>
 : ${HOGE:?"Error HOGE is empty"} : ${HOGE:?"Error HOGE is empty"}
 </code> </code>
行 201: 行 366:
 可読性を考えると普通にifで書いた方がいいかも… 可読性を考えると普通にifで書いた方がいいかも…
  
-<code> +<code bash
-if [ -z "${HOGE}]; then+if [[ -z ${HOGE} ]]; then
   echo "Error HOGE is empty" >&2   echo "Error HOGE is empty" >&2
 fi fi
行 220: 行 385:
 ファイルディスクリプタ0番がterminalに紐づいている(=パイプやリダイレクトによるデータの入力がされていない) ファイルディスクリプタ0番がterminalに紐づいている(=パイプやリダイレクトによるデータの入力がされていない)
  
-<code>+<code bash>
 if [ -t 0 ]; then if [ -t 0 ]; then
    # パイプやリダイレクトされてない    # パイプやリダイレクトされてない
行 237: 行 402:
 ''$1'' ''$2'' で引数を取得できる。引数の数は ''$#'' で取得できる。引数の数が2桁になる場合は ''${10}'' のように {} で括る。 ''$1'' ''$2'' で引数を取得できる。引数の数は ''$#'' で取得できる。引数の数が2桁になる場合は ''${10}'' のように {} で括る。
  
-<code>+<code bash>
 # arg1.sh # arg1.sh
 echo $# echo $#
行 244: 行 409:
 </code> </code>
  
-<code>+<code bash>
 $ ./arg1.sh a b c d $ ./arg1.sh a b c d
 4 4
行 254: 行 419:
 ''$@'' または ''$*'' でシェルスクリプトの引数全体を取得できる。  ''$@'' または ''$*'' でシェルスクリプトの引数全体を取得できる。 
  
-<code>+<code bash>
 # arg2.sh # arg2.sh
 echo $@ echo $@
行 260: 行 425:
 </code> </code>
  
-<code>+<code bash>
 $ ./arg2.sh 1 2 3 $ ./arg2.sh 1 2 3
 1 2 3 1 2 3
行 266: 行 431:
 </code> </code>
  
-''$@'' と ''$*'' はダブルクオートで括った場合の動作が異なる。''$*''引数が一つの値にまとめられてしまう。ほとんどの場合、''$@'' の挙動が求められるので、''$@'' を使っておけば間違いない+''$@'' と ''$*'' はダブルクオートで括った場合の動作が異なる。''"$@"''は''"1" "2" "3"''、''"$*"''は''"1 2 3"''と展開される。
  
-<code>+ 
 +''$*'' は引数が一つの値にまとめられてしまう。ほとんどの場合、''$@'' の挙動が求められるので、''$@'' を使っておけば間違いない 
 + 
 +<code bash>
 # arg3.sh # arg3.sh
 node -p -e 'process.argv.slice(1).join()' -- "$*" node -p -e 'process.argv.slice(1).join()' -- "$*"
行 277: 行 445:
 </code> </code>
  
-<code>+<code bash>
 $ ./arg3.sh 1 2 3 $ ./arg3.sh 1 2 3
 1 2 3 1 2 3
行 287: 行 455:
 ''$*'' をダブルクオートで括った場合、空白スペースで結合される。結合文字は環境変数IFSで変更できるが影響範囲が大きいのであまり変えない方が良いだろう。 ''$*'' をダブルクオートで括った場合、空白スペースで結合される。結合文字は環境変数IFSで変更できるが影響範囲が大きいのであまり変えない方が良いだろう。
  
-<code>+<code bash>
 # arg4.sh # arg4.sh
 echo "$*"  echo "$*" 
行 294: 行 462:
 </code> </code>
  
-<code>+<code bash>
 $ ./arg4.sh 1 2 3 $ ./arg4.sh 1 2 3
 1 2 3 1 2 3
行 304: 行 472:
 ===== ヒアドキュメント ===== ===== ヒアドキュメント =====
  
-==== 変数に格納 ====+変数に格納
  
-<code shellscript+<code bash
-hoge=$(<< 'EOS' +val=$(cat << 'EOS' 
-a = ARGV.first.split("=").last +hoge 
-puts a.gsub(/^\//, "https://")+fuga 
 +piyo
 EOS EOS
 ) )
 +</code>
 +
 +
 +標準入力に渡す
 +
 +<code bash>
 +while read -r line
 +do
 +  echo $line
 +done << 'EOS'
 +hoge
 +fuga
 +piyo
 +EOS
 +)
 +</code>
 +
 +
 +一度変数を経由する。''<<<''はヒアストリングと呼ばれるものでPOSIXには定義されておらずshでは使用できない。bashやzshで使用できる
 +
 +<code bash>
 +val=$(cat << 'EOS'
 +hoge
 +fuga
 +piyo
 +EOS
 +)
 +
 +while read -r line
 +do
 +  echo $line
 +done <<< $val
 +</code>
 +
 +クオートの有無は変数展開するかしないか
 +
 +<code bash>
 +val='test'
 +
 +while read -r line
 +do
 +    echo $line
 +done << "EOF"
 +${val}
 +${val}
 +${val}
 +EOF
 +</code>
 +
 +クオートありの場合は変数展開されずに以下のように出力される
 +
 +<code>
 +${val}
 +${val}
 +${val}
 </code> </code>
  
shellscript.1585720082.txt.gz · 最終更新: by nullpon