改行
l\s
出力を表示しない
echo 'Hello' > /dev/nullエラーを表示しない.
echo 'Hello' 2> /dev/null出力とエラーどちらも表示しない.
echo 'Hello' > /dev/null 2>&1終了ステータス
bashでは0が真
trueやfalseの後に$?を参照すると, 終了ステーテスが得られる.
何か コマンドを実行した後に$?を参照すると終了ステータスがわかる.
例
cat hoge.txt
echo $?
#>0! cat hoge.txt
#>1(逆になる.)echo $?
パイプライン
コマンド1 | コマンド2
コマンド1の出力をコマンド2に渡して実行する.
&&リスト
コマンド1 && コマンド2
コマンド1が実行され, 終了ステータスが0なら, コマンド2が 実行される
cmp -s file1 file2 && {
echo '重複ファイルfile2を削除します.'
rm -f file2
}
||リスト
コマンド1 || コマンド2
どちらかが真なら, 終了ステータスが真になる.
つまり, コマンド1が真なら, コマンド2は実行されない.
test -f file1 || {
echo 'file1が存在しません'
exit 1
}
if文
if [ "$i" -eq 3 ]
then
echo "3です"
elif [ "$i" -eq 5 ]
then
echo "5です"
else
echo "3,5以外です."
fi
case
case文ではinの後ろに何も書かない. caseの後ろはvarではなく$varとしなければならないcase $1 in
start)
echo 'start';;
stop)
echo 'stop';;
*)
;;
esac
////////////////////////////
コマンドを使うこともできる. コマンドは「`」(@+shift)で囲む.case `uname -s` in
Linux|FreeBSD)
echo 'osはLINUXかFreeDOSです'
;;
*)
echo 'そのほかのOSです'
;;
esac
リストの継続実行//エラーが出て使えない.
case $var in
one)
echo '$varがoneの場合'
;&
two)
echo '$varがoneまたはtwoの場合'
;;
esac
パターンの継続探索//エラーが出て使えない
case $var in
one)
echo '$varがoneの場合'
;;&
two)
echo '$varがtwoの場合'
;;&
*)
echo '全ての場合'
;;
for文
カレントディレクトリの全てのファイルについて行う
もちろん*ではなく*.txtなどとしても良い
for file in *
do
cp -p "$file" "$file".bak
done
シェルスクリプトの引数の文だけループ
for file in "$@"
do
cp -p "file" "file".bak
done
コマンド置換を使ったfor文
filelinstというファイルに以下のようなファイル名を箇条書きにしたものを用意する.
memo.txt
prog.c
figure.png
hoge.txt
コマンド置換を使ったfor文
for file in ´cat filelinst´
do
cp -p "file" "$file".bak
done
continueを使う方法
for文の中で組み込みコマンドcontinueを実行すると, その回のループの残りの部分を実行せず, 次の回のループに進む.
すでにbakというファイルがある時, コピーしない
for file in *
do
case $file in
*.bak)
continue
;;
esac
cp -p "file" "file".bak
done
値として特殊な意味を持つ記号を使う場合は, クォートが必要
for i in ';' '\' '('
算術式のfor文
2重かっこで囲まなければならない.sum = 0
for ((i=1; i <100; i++)) {
((sum += i))
}
echo "$sum"
while文
while文ではexprコマンドでよく加算する
そのほかにシェルの位置パラメータをシフトさせるshiftコマンドが使用されることもよくある
i=´expr "$i" + 1´は((i++))という表現でも良い
sum=0
i=1
while [ "$i" -le 100 ]
do
sum =´expr "$sum" +"$i"´
i=´expr "$i" + 1´
done
echo "$sum"
シェルスクリプトの引数の分だけループ
シェルスクリプトの引数の個数が入っている特殊パラメータ$#の値が「0」になるまでループを繰り返す.
次のループのた目にshiftコマンドで引数をずらす.
$#の値はshiftのたびにデクリメント(-1)されることに注意
while [ $# -gt 0 ]
do
cp -p "$1" "$1".bak
shift
done
while文の中にcase文を記載
while文+case文+shiftでオプションの処理を行うことが常套手段となっている。suffix=.bak
dir=.
while [ $# -gt 0 ]
do
case $1 in
-s)
suffix="$2"
shift
;;
-d)
dir="$2"
shift
;;
*) break
;;
esac
shift
done
while [ $# -gt 0 ]
do
cp -p "$1" "$dir"/"$1""$suffix"
shift
done
select文
選択メニューを表示し, ユーザの入力を受け付ける
breakコマンドが実行されるか, 標準入力がEOFになると終了
通報はCtrl + D を入力すると標準入力がEOFになる
PS3='コマンド?'
select cmd in up down left right look quit
do
case $cmd in
up)
echo '上に移動しました' ;;
right)
echo '下に移動しましt' ;;
look)
echo 'アイテムが落ちています' ;;
quit)
echo '終了します'
break;;
*)
echo "$REPLY"'というコマンドはありません';;
esac
echo
done
サブシェル
カレントティれクトリの一時変更や, シェル変数の局所的な使用などの, もとのシェルの状態には影響を及ぼさずに, 一定の処理を行いたい場合, その部分のリストを()で囲んで, リストをサブシェルで実行させるようにする. サブシェルは, もとのシェルとは別の子プロセスになるため, 子プロセス状のカレントディレクトリやシェル変数などが変化しても, もとのシェルには影響しません.
サブシェル内では, シェル変数への代入のほか, シェル変数やその他のパラメータの操作に関する, export/read/readonly/set/shift/unsetなどのコマンドの効果がサブシェル内のみになります.
そのほか, cd/umaskコマンドについても, 影響がサブシェル内だけになり, exec/exitコマンドではもとのシェル状での動作とは異なる動作になります.
サブシェルの標準出力のリダイレクト
(
cd /some/dir
pwd
ls -l
) > logfile
グループコマンド
複数のコマンド(パイプライン)を改行や; などでつなげばリストになり, リストはそのままif文/for文など の構文の要素になれます. しかし, リスト全体のまままとめてファイルにリダイレクトしたり, パイプに通してりしたい場合, リスト全体をいったん1つのコマンドとして, まとめる必要がある.
{}で囲むことにより, 全体が一つのコマンドになる.
{
uname -a
date
who
} > logfile
これは,uname -a >logfile
date >> logfile
who >> logfile
という野暮ったい書式を簡潔に表現できる.
引数を再度解釈し, コマンドを実行する.
day=Mondaytoday=day
eval echo \"\$$var\"
まず, シェルに一回解釈されて, echo "$day"となり, echo Mondayになる.
シェル関数
例えば, 再起をつかって階乗を計算する.#!/bin/bash
func()
{
if [ "$1" -le 1 ]
then
echo 1
return
fi
n=`expr "$1" - 1`
n=`func "$n"`
expr "$n" * "$1"
}
func "$1"
ローカル変数
func(){
local i
i=5
}
算術評価
少数は無理(( ))で囲まれた部分は, 算術式とみなされ, 演算子を使った評価ができる. シェル変数は$の記号をつけずに参照できる.ほぼc言語と同じ演算子が使える。
条件式の評価
if [[ "$i" -le 3 || "$i" -le 5 ]]
then
echo 'iの値は3か5です.'
fi
&&, ||, ==, !=という演算子が[[]]を2重にすることで使えるようになる.
何もしないで単に0の終了ステータスを返す.「:」
:${1?'引数を指定して下さい'} #引数を指定しなければ, エラーメッセージ: >file #新規ファイル作成
他には, if文でelseのみを実行したい時に使ったりする.
パラメータのデフォルトのデフォルトの値を指定する
cp file "${$1:=/tmp}
これは, 以下と同様
if [ -n "$1" ]
then
cp file "$1"
else
cp file /tmp
fi
パラメータにデフォルトの値を代入する
cp file "${TMPDIR:=/tmp}
これは, 以下と同様
if [ -z "$TMPDIR ]
then
fi
cp file "$TMPDIR"
以下とも同様
: ${TMPDIR:=/tmp}
cp file "$TMPDIR"
パラメータが設定されていれば, 指定の値に展開する.
${var:+値}パラメータ未設定時にエラーメッセージを出してシェルスクリプト を終了させる
引数1で指定されたファイルを/tmpにコピーし, 引数1が未設定または, 空文字列の場合はエラーメッセージを出す
cp "${1:?ファイルが指定されていません}" /tmp
これは以下と同様
if [ -z "$1" ]
then
echo 'ファイルが指定されていません'
exit 1
fi
cp "$1" /tmp
パラメータの文字列の長さを求める
echo ${#var}
パラメータの値の文字列の左側から一定のパターンを取り除く
${パラメータ#パターン}
パラメータの値の文字列の左側からパターンに一致する最短の文字列が取り除かれる
${パラメータ##パターン}
パラメータの値の文字列の左側からパターンに一致する最長の部分が取り除かれる.
拡張子だけを取り出す
F_NAME="hoge.txt"
echo "${F_NAME##*.}"
#>txtパラメータの値の文字列の右側から一定のパターンを取り除く
パラメータの値の文字列の右側からパターンに一致する最短の部分が取り除かれる.
${パラメータ%パターン}
パラメータの文字列の右側からパターンに一致する最良の部分が取り除かれる.
${パラメータ%%パターン}
拡張子を取り除く
F_NAME="hoge.txt"
echo "${F_NAME%.*}"
#>hogeオフセットや長さを指定してパラメータの値の文字列を切り出す.
シェル変数varの左側の2文字を除いて残り5も自分を表示
echo "${var:2:5}
シェル変数varの左側の2文字を除く
echo "${var:2}
パターンを指定してパラメータの値の文字列を置換する
パラメータの値の文字列の左側から見て最初にパターンに一致した文字列の部分が置換文字列に置換される
${パラメータ/パターン/置換文字列}
パラメータの値の文字列の左側から見てパターンに一致した文字列の部分全てが置換文字列に置換される
${パラメータ//パターン/置換文字列}
指定した文字列で始める変数名を一覧表示する
Pで始まるシェル変数名を全てリストする
echo ${!P*}またはecho ${!P@}
間接参照${!パラメータ}
パラメータの値をパラメータ名とみなし, さらにその値を参照する
message=hello
var=message
echo "${!var}"
#>helloシングルクォート
echo '$5は5ドルの意味です'
文字列をシングルクォートで囲むと, 文字列の各文字全てが特殊な意味を失い, 文字通りの意味として解釈される. ただし, シングルクォート自体は含めることはできない.
文字列中でシングルクォートを使いたい場合は, いったんシングルクォートを抜けて\'を使う
echo 'Let'\''s go !'
ダブルクォート
文字列をダブルクォートで囲むと$, ´, \を除き, 文字列の各文字が特殊な意味を失う
シェル変数などんパラメータ展開の際に, 単に$varのようにして参照すると, シェル変数の値に含まれるスペースや*などの文字列が解釈されてしまう. これを避けるためにシェル変数の参照時に, "$var"のようにダブルクォートで囲むのが基本.
コマンド置換
コマンド置換では, バッククォート(``)で囲まれたリストが実行され、この結果, 標準出力に出力された文字列で, ``の部分が置き換えられる. 標準出力の最後に改行コードが付いている場合は, 取り除かれる.
$, ´, \の直前の\については特別に解釈される
i=3
echo "$i"
#>3i=`expr "$i" + 1`
#>4$( )
`リスト`と$(リスト)は同じ
ただし, ``によるコマンド置換と異なり, $( )中は, \\, \$, \`が特別に解釈されることがない.*
0文字以上の任意の文字列
?
任意の一文字
[]
指定した条件の一文字
[123]
[a-z]
[!a-d] #abcd以外の1文字[a-zA-Z0-9_-] #全ての英数字, アンダースコア, ハイフン
複数の文字列の組み合わせから文字列を生成する
cp /some/dir/{cat,dog}.jpg .
/some/dirの下にあるcat.jpg, dog.jpgをカレントディレクトリにコピー
パス展開とは異なり, 現在のパス名との照合は行われません.
エラーメッセージのリダイレクト 2>
エラーメッセージを出さずに/some/dirというディレクトリを削除する
rmdir /some/dir 2> /dev/null
読み書き両用open
cat <> fileヒアストリング
ヒアドキュメントよりも単純に記述できる.cat <<< 'hello world >file.txt
hello world2
hello world3'
ヒアドキュメント
コマンド <<[-] 'EOF'
ヒアドキュメント本体
EOF
ヒアドキュメントによるメールの送信
nkf -j << 'EOF' | mail guest@example.com
このメールは
ヒアドキュメントによる
メールの送信です
EOF
#nkfは文字コードと改行コードを変換するためのコマンド-jはjis, -eはeucファイル名からディレクトリ名の部分や拡張子を取り除く
basename ファイル名 .拡張子
name=`basename /some/dir/memo.txt .txt`
echo "$name"
#>memo拡張子のリネーム
for file in *.txt
do
name=´basename "file" .txt´
mv "$name".txt "$name".html
done
ファリル名の部分からそのディレクトリ名部分を取り出す
dirname ファイル名
配列
array[3]='hello world'
echo "${array[3]}"
#>hello worldi=4
echo "array[i-1]"
#>hello world配列の一括代入, 一括参照
array=(one two three)
echo "${array[@]}"
#>one two three配列を配列に一括代入
array2=("${array1[@]}")
ファイル名に日付文字列を含ませせる
mycomand > log`date +%Y%m%d%H%M%S`
%Y 年
%m 月
%d 日
%H 時
%M 分
%S 秒
ファイルを1行ずつ読んでループする
ファイルから1行ずつ読み込み, その内容を解釈しつつループするには, while readの形式を使う. readコマンドは標準入力から1行ずつシェル変数に読み込み, 入力がEOFになると偽(1)の終了ステータスを返す. よって, while readの形でループを記述すれば, 1行ごとにファイル全体にわたってループすることができる.
readコマンドの引数に複数のシェル変数を指定すると, シェル変数IFSの値を区切り文字として単語に分割された結果が複数のシェル変数に分割して代入されるため, これを利用して簡単な字句解析ができる.
/etc/hostsを1行ずつ読み込みながらループし, シェルスクリプトの引数で指定されたIPアドレスに一致する行を見つけたらそのホスト名部分を表示して終了するシェルスクリプト
case $# in
1)
;;
*)
echo "Usage: $0 ip_adress" 1>&2
exit 1
;;
esac
#ファイル記述子「3」を使って/etc/hostsを読み出しオープンexec 3< /etc/hosts
#ファイル記述子3から1行ずつ読み込んでループwhile read ip host 0<&3
do
case $1 in
$ip)
echo "$host"
exit 0
;;
esac
done
#ファイルクローズ, 省略可能exec 3<&-
#一致するIPアドレスが見つからなかったecho "&1 not found" 1>&2
exit 1
while文全体に直接リダイレクトする方法
case $# in
1)
;;
*)
echo "Usage: $0 ip_adress" 1>&2
exit 1
;;
esac
while read ip host
do
case $1 in
$ip)
echo "$host"
exit 0
;;
esac
done < /etc/hosts
#一致するIPアドレスが見つからなかったecho "&1 not found" 1>&2
exit 1
シェルスクリプト の引数につけられたオプションを解析する.
-c, -i, -v 変数, -o 変数を解析する
#!/bin/bashwhile getopts civ:o: option
do
case $option in
c)
echo '-cオプションが指定されました';;
v)
echo '-vオプションが指定されました';;
i)
echo '-iオプションで'"$OPTARG"'が指定されました.';;
o)
echo '-oオプションで'"$OPTARG"'が指定されました.';;
#不正なオプション
\?)
echo "Usage: $0 [-c] [-v] [-i file] [-o file] [args...]" 1>&2
exit 1;;
esac
done
#OPTINDから1を引いた数だけ一パラメータをshift
shift `expr "$OPTIND" - 1`
if [ $# -ge 1 ]; then
echo 'オプション以外の引数は'"$@"'です'
else
echo 'オプション以外の引数はありません'
fi
標準入力をシェル変数に読みこむ
echo -n 'prompt> ' 1>2&
read input
testコマンドで使用可能な演算子
数値の比較
意味 if文で使う例
n >= y if [ n -ge y ]; then
n <= y if [ n -le y ]; then
n > y if [ n -gt y ]; then
n < y if [ n -lt y ]; then
n = y if [ n -eq y ]; then
n != y if [ n -ne y ]; then
文字列の比較
if [ "n" = "y" ]; then
if [ "n" != "y" ]; then
ディレクトリ/ファイルのテェック
パスがファイルか if [ -f path ]; then
パスがディレクトリか if [ -d path ]; then
Aファイルが存在するか if [ -e fileA ]; then
Aファイルが空じゃないか if [ -s fileA ]; then
Aファイルが読取可能か if [ -r fileA ]; then
Aファイルが書込可能か if [ -w fileA ]; then
Aファイルが実行可能か if [ -x fileA ]; then
複数条件
条件Aかつ条件B if test [ A ] -a [ B ]; then
条件Aまたは条件B if test [ ... ] -o [ ... ]; then
cutコマンド
「cut」は、ファイルを読み込んで、それぞれの行から指定した部分だけを切り出すコマンドです。-d文字 #フィールドの区切り文字として, タブの代わりに使用する文字を指定する.
コントロールキー
ctrl+c #現在のキーを終了するctrl+d #入力を終了する.
ctrl+\ #ctrl+cが効かない場合に, 現在のコマンドを終了する.
ctrl+s #画面への出力を停止する
ctrl+q #画面への出力を再開する
dellまたは, ctrl+? #最後の文字を削除する
ctrl+u #コマンドライン全体を削除する
ctrl+z #現在のコマンドを一時停止する
ctrl+d #前方削除
esc+b #後方に1ワード移動
esc+f #前方に1ワード移動
esc+del #後方に1ワード削除
esc+d #前方に1ワード削除
ctrl+y #最後に削除されたものを取り消す
ctrl+a #コマンドラインの先頭へ移動
ctrl+e #コマンドライン末尾へ移動
ctrl+k #コマンドラインの末尾まで削除
環境のカスタマイズ
ホームディレクトリにある3つのファイルは, bashにとって特別な意味を持つ..bash_profile, .bash_logout, .bashrc
.bash_profileを変更する際は, 既存の行の後ろに付け加えるようにしよう.
alias 名前=コマンド .bash_logoutはログアウト時に一時ファイルを削除したり, システムにログインしていた時間を記録したりするコマンドを実行したい場合に設定する
シェルスクリプトのコメント
ヘッダー #################################### # # Name: # 目的 # # Usage: 使い方 # # Date ######################################定数には大文字を使用し, 通常は読み取り専用として, 宣言する
declare -r CAPIRTAL_OF_ENGLAND="London"コードをマジックナンバーだらけにするのは良くない
if [[$prosess_result == 68 ]]次のように書き換える
declare -ir STAGE_3_FAILURE=68
if [[$prosess_result == STAGE_3_FAILURE ]]
関数の中で変数を代入すると値は関数外でも変わる
function afunc{
var1="in function"
echo $var1
}
var1="out function"
echo $var1
afunc
echo $var1
# 実行結果
# out function
# in function
# in function
関数内での変数の代入を関数外で反映させないためには localを使う
function afunc { local var1="in function" }10より大きい番めの位置パラメータ
${10}としなければならない置換演算子
${variable:-word} #variableが存在すればその値を返す. 存在しなければwordを返す. variable自体に代入されるわけではない${variable:=word} #variableが存在すればその値を返す. 存在しなければvariableにwoedを代入して返す. variable自体に代入される.
${variable:?message} #variableが存在し, かつ, nullでない場合にその値を返す. それ以外の場合はvariable:に続いてmessageを出力し, 現在のコマンドスクリプトを終了する
${variable:+word} #variableが存在し, nullでない場合にwoedを返す.
${variable:offset:length} #$variableの値からoffsetのいちからlength文字の長さの部分文字列を取り出す
パターン
${variable/pattern/string} #variableの値でpatternと最初に一致した最も長く一致した部分をstringと置換する. ${variable//pattern/string} #variableの値でpatternと最も長く一致した部分全てがstringに置換される. stringがnullの場合は一致した部分が削除される. variableが@または*の場合には, 位置パラメータが順番に処理され, 展開結果がそのリストとなる.型を持つ変数
val1=2val2=3
declare -i result #整数型
result=val1*vcal2
echo "$result" #>12
算術, 整数
$(())で囲むと算術演算式として解釈されるecho "only $(( (365-$(date +%j)) /7))" week until the New Year"
条件式
エスケープされたかっこ\( \)を使わなければならない[ \( 3 -gt 2 \) && \( 4 -le \) ]
これは以下と同じ
[ $(((3 > 2 )) && (4 <= 1)))=1 ]
デバッグ
最も簡単なのはechoで出力することset -oコマンド
$ set -o xtrace
なんか色々あるけど理解できなかった
until
whileと条件判断が逆.until [ ]
print '数字は%dです.\n' "$i"
言語の一時変更
LANG=C dateホームディレクトリが設定されているシェル変数
$HOMEチルダ展開 ~ と同じ.
sleep
15秒間停止sleep 15
.tar.gz/.tar.bz2自動展開
#!/bin/shdir=${2-/tmp} #省略時はtmpの中に作成される.
case $1 in
*.tar.gz|*.tar.Z)
tar zxvf "$1" -C "$dir"
;;
*.tar.bz2)
tar jxvf "$1" -C "$dir"
;;
*)
echo "$1"'の展開方法が不明です.' 1>&2
exit 1
;;
esac
プログレスバー
