// 検索用:シェルスクリプト -[[シェルプログラミング]] *概要 [#fc9dc96c] -ShellScriptの書き方 -bashができれば大体shもできるので、bashメイン -[[シェル芸の問題と解答を公開しているサイトがある>https://blog.ueda.asia/?page_id=1434]] *下位ページ [#u40b2348] -[[parallel]] *目次 [#r1aa2f8f] #contents *計算 [#i7d529a0] VAR_LEFT=5 VAR_RIGHT=5 echo $(($VAR_LEFT + $VAR_RIGHT)) echo $(($VAR_LEFT - $VAR_RIGHT)) echo $(($VAR_LEFT * $VAR_RIGHT)) echo $(($VAR_LEFT / $VAR_RIGHT)) echo $(($VAR_LEFT % $VAR_RIGHT)) *デバッグ [#ce6b68df] -''下らないミスをなくすために、必ず以下をかくこと'' #!/bin/bash -コマンド展開 sh -x test_eval_1.sh #展開後実際に起きていることがわかる *bashとshの違い [#kd458d71] -リダイレクト先にメタ記号を使えない *文法 [#k4b2ce77] **if [#r2c7666a] if [ $? -eq 1 ] # []の回りにスペース必須 then continue fi **for [#ffbb6397] -for文ではcontinue可能 **終了ステータス [#pd463b87] -$?で終了ステータス --grepで見つかったかどうかなどが分かる **配列 [#p79c8cfc] list=("1332" "1333" "1605") # =の間にスペースを入れると死ぬ **include [#t49c5f59] . list #listは実行可能である必要は無い *find [#u16ed6c4] find . find . -type f find . -type ! -name "*~" find . -type f -a \( -name "*.c" -o -name "*.h" \) -なぜかfind . -type ! -name *~は動作しない。 --hoge*, "hoge*", 'hoge*'の違いが知りたい --$"とかもあるの?" *xargs [#r5740fd6] ls -1 | xargs echo find . -print0 | xargs -0 echo find . -print0 | xargs -0 -L1 echo find . -print0 | xargs -0 -L2 echo find . -print0 | xargs -0 -I{} echo "<{}>" -findからxargsにパイプする場合は、絶対findの$最後に$-print0をいれてxargsに-0を入れる。 ls | sed -e "p;s/\.jpeg$/\.jpg/" | xargs -n2 mv for i in *.jpeg ; do mv $i `basename $i .jpeg`.jpg ; done -頑張ってmv, cpなどの二つ同じものが出てくる場合は、このようにsedの;セパレータと-n2で頑張る --sifiたんありがとうございます。 *sed [#nf83901b] -オプション-Eで拡張正規表現も使える。 sed -e 's/#//' -Hitしなければそのまま表示、Hitすれば処理をして表示 sed -n 's/#//' -Hitしてもしなくても非表示 sed -n 's/#//p' -Hitすれば処理をして表示 --そもそもHitしているか、何回Hitしているかを確認するために、-eにpをつけることもある。 echo 'a a' | sed -e 's/ *//' -出力は"a a" --なぜなら、1つ目のaの前にマッチするから。 sed -e '1s/rep/p/' -1行目のrepをpに変換 --行数の指定は一番初めに書く。指定方法は ---1: 1行目 ---1,10: 1行目から10行目 ---1,+10: 1行目から11行目 ---^,$: 行頭から行末まで --など -sedは{とか}をエスケープ必要がある --でもgrepはそうでもない --どういうのがエスケープ必要で、必要ないの? --Sedは1行でマッチする文字が何通りもある場合は、一番長いものにマッチする。(sed ‘[l],[r]s/<[^<]*>//’の時、前半はオンオフで制御され、後半はきちんと最長一致で制御されている。) *awk [#h7233819] -awkで置換 echo "replot" | awk '{sub(/^rep/, "p", $0); print $0}' *make [#x6fb5be5] Makefileの$のエスケープは$$ *backquote [#l969c4cb] echo hamu echo `echo hamu` echo `echo \`echo hamu\`` echo `echo \`echo \\\`echo hamu \\\`\`` *for文 [#p2ca5082] for var in `echo "a b"` do echo ${var} done for var in `echo "a b"` ; do echo ${var} ; done -1行の場合は、doの後に;を入れてはならない -1行にする場合は二つ目のechoの後の;が必須。ないとechoがdoneを食ってしまう。 *セパレータ [#zfc117e2] #!/bin/bash IFS=$'\n' for i in `cat file` do IFS=$' \t\n'で echo $i done * $'' [#k2bcd27c] 中の\t, \b, \nなどを展開する。~ これはalt-v [tab], alt-v [backspace], alt-v [enter]に相当する。~ echo "a\na" \n echo $'a\na' a a * while [#k4a395c3] while read i;do echo $i;done < file -1行の場合は、doの後に;を入れてはならない *文字列の比較 [#uaeea0c4] ${var} = "A" ${var} != "A" -if [ ${var} = A ]と何が違うの?違わないとしたら""の意味は何? *何もしない [#d1655e85] : *if [#c1fe8662] -中のコマンド実行結果が0ならthenを実行する構文。 if command then expression fi if command ; then echo a ; fi -空文字列判定 if [ -z "${opts}" ]; then echo "null stream" else echo "not null stream" fi -空ファイル判定 if [ -s test.txt ]; then echo "exist" else echo "not exist" fi -ダブルクオーテーションで囲まないとだめ *test [#ka1ed772] -testと[は同じ意味。 if [ condition ] then expression fi if [ -e hoge ] ; then echo a ; fi -一行の時はthenの後に改行を入れてはならない。 *grep, egrep [#d65fa98d] -egrepはgrepの正規表現が新しいバージョン。+, ?が使える。~ -実行結果は、検索に引っかかったら0, 引っかからなかったら1 echo $' \t' | grep $'^[ \t]+$' ; echo $? 1 echo $' \t' | egrep $'^[ \t]+$' ; echo $? 0 -ちなみに-Eをつけるとegrepと同じ動作に --これはsedでも同じ挙動をする echo $' \t' | grep -E $'^[ \t]+$' ; echo $? 1 *$?とパイプ [#b40c18e9] echo "hoge" | grep "test" | echo $? -出力をechoが食おうとしているから、grepの終了コード1を正常に取得できない。 echo "test" | grep "test" ; echo $? -grepが終わってからechoしているので、1が表示される *Gnuplot [#t558cb62] **式 [#oa960a00] plot "file" u 1 plot "file" u ($1) -uの後は、カッコでくくると式モードになって、1などは$1などにしなければいけなくなる。 **for [#x65e72f2] -a 1 2 3 2 3 2 3 5 2 5 8 1 plot for [i=1:3] "a" u i **sprintf [#j6e08031] plot for [i=1:3] sprintf("hoge%02d", i) t sprintf("hoge%02d", i) -hoge01, hoge02, ...をplot **system [#m0de8670] -num.config 3 num = system("cat num.config") plot for [i=1:num] sprintf("hoge%02d", i) t sprintf("hoge%02d", i) **数字と文字列の連結 [#c281e897] n = system("awk '{print NF; exit}' motenc_state") replot for [i=2:n] "dv_motor" u i title "Motenc State".(i-1)." [unknown]" *awk [#c267cf70] **1行目のフィールド数の取得 [#kb24f72c] awk '{print NF; exit}' file *complete [#uc6529f6] **complete [#d82ec31d] complete -o dirnames -f -X '!*.mp3' mp3nantoka.sh -COMPREPLYの中を候補に表示する「だけ」 comptest2 () { COMPREPLY=( aaa bbb ) } complete -F comptest2 hoge hoge [tab][tab] **comgen [#q7595d2b] -aaa, bbbを候補に表示し、補完 comptest1 () { COMPREPLY=( `compgen -W "aaa bbb" $2` ) } complete -F comptest1 hoge hoge [tab][tab] **定石 [#y47f6b13] function _hoge { local arg opts COMPREPLY=() arg="${COMP_WORDS[COMP_CWORD]}" opts="`ls -1`" IFS=$'\n' COMPREPLY=($(compgen -W "${opts}" -- ${arg})) unset IFS } complete -F "_hoge" "hoge" **Directoryのパスの場合 [#n67f5b4f] complete -F "_plotter" -o "nospace" "plotter" -nospaceのoptionをつけると、最後にスペースが入らなくて良い *Dropbox [#i7ad47e7] ~/.dropbox-dist/dropboxd *自動起動 [#r22b5c8e] Startup Aplicationからクリックで頑張る *wget [#a55b816b] -URLのソースコードを取得する wget https://twitter.com/ *cron [#x371505d] -cronの設定を行う。書式はググる。 crontab -e crontab -l -例 --cron_has_calledはデフォルトでhomeに出力されるようになっている。 23 * * * * echo "hallo" >> cron_has_called *mail [#we0733a2] echo "test" | mail wakataberyo@gmail.com *sendmail [#m48aac2b] -headerを明示的に書く必要があるのと、mailに比べて愚直である。 -headerの例(最後は改行が必要) Content-Type: text/plain; charset=iso-2022-jp Subject: test -使い方 cat header honbun | sendmail wakataberyo@gmail.com *md5sum [#i912ec90] -文字列をハッシュにする。 echo "test" | md5sum d8e8fca2dc0f896fd7cb4cb0031ba249 - -ハイフンには標準入力という意味がある。 *iconv, nkf [#qd24fdf2] -文字コード変換 -iconv --文字コードをFROMからTOにする。 --半角カナ文字が入っていると対応できないので、日本語を扱うときには基本的にnkfを使う。 iconv -f FROM -t TO -nkf --文字コードをguessしてISO-2022-jpにする cat file | nkf -j --文字コードをguessしてSHIFT-JISにする cat file | nkf -s |