「Bash」の版間の差分

提供: Wikinote
移動: 案内検索
(プロンプトに色を付ける)
 
(同じ利用者による、間の40版が非表示)
行1: 行1:
''bash を制するものが、Linux を制す —— hagio''
+
== 参考文献 ==
 
+
* [http://mywiki.wooledge.org/BashFAQ BashFAQ - Greg's Wiki] これはすごい。特に以下の項目がためになる。
* <code>export</code> は、その変数を子プロセスに引き継ぐ場合に用いる。
+
** [http://mywiki.wooledge.org/BashFAQ/031 What is the difference between test, [ and [[ ?]
* Meta キーは ESC キーで代用可。(Poderosa では有用)
+
** [http://mywiki.wooledge.org/BashFAQ/082 Why is $(...) preferred over `...` (backticks)?]
 +
* [http://mywiki.wooledge.org/BashPitfalls BashPitfalls - Greg's Wiki] bash の落とし穴。これも必見。
  
 
== シェルスクリプト ==
 
== シェルスクリプト ==
* $# - 引数の個数なので、スクリプト名は含まない。
+
* $# - 引数の個数なので、スクリプト名は含まない。(要は最後のインデックス)
 
* [http://www.linux.or.jp/JF/JFdocs/Bash-Prog-Intro-HOWTO.html BASH Programming - Introduction HOW-TO]
 
* [http://www.linux.or.jp/JF/JFdocs/Bash-Prog-Intro-HOWTO.html BASH Programming - Introduction HOW-TO]
 +
* <code>$'string'</code> の形式で特殊文字を出力できる。<code>$'\x30' = '0'</code> など。
 +
* $(cat file) とするなら、$(< file) の方が fork しないので速い。
  
== コマンド ==
+
=== 配列 ===
* 行末までキル:C-k
+
迷宮入りするかと思うほど理解するのが難しかった。。
* 行頭までキル:C-u
+
* 初期化 <code>array=(hoge fuga piyo)</code>
 +
** インデックス指定 <code>array=([2]=piyo [0]=hoge [1]=fuga)</code> は↑と同じ配列。
 +
* 参照 <code>${array[1]}</code>
 +
* 要素数 <code>${#array[@]}</code>
 +
 
 +
==== コマンド実行結果を 1 行ごとに配列に格納する ====
 +
区切り文字を改行にしておかなければ、1 行ごとに格納されない。
 +
IFS=$'\n'
 +
array=( $( ls -l ) )
 +
 
 +
==== 配列に要素を追加 ====
 +
これもハマった…。一旦展開するのがポイント。
 +
array=( "${array[@]}" "hoge" )
 +
 
 +
=== パラメータ展開 ===
 +
スクリプトを書く際には便利なものの、忘れがちなので書いておく。
 +
${parameter#pattern}  前方最短一致部分を削除
 +
${parameter##pattern}  前方最長一致部分を削除
 +
${parameter%pattern}  後方最短一致部分を削除
 +
${parameter%%pattern}  後方最長一致部分を削除
 +
わかりにくいので使用例を示す。
 +
* コマンドのパスから、そのコマンドがあるディレクトリのパスを得る
 +
$ CMD_PATH=/usr/local/bin/hoge
 +
$ echo ${CMD_PATH%/*}
 +
/usr/local/bin
 +
* ファイル名から、拡張子だけを取り出す
 +
$ FILE_NAME=hoge-1.2.txt
 +
$ echo ${FILE_NAME##*.}
 +
txt
 +
 
 +
=== 無限ループ ===
 +
こいつで 1 セクション作るのはどうかと思うが…、他に見出しを付ける方法がないので。
 +
while :
 +
do
 +
  ''command''
 +
done
 +
<code>while</code> に真を渡す方法はいくつかあるが、bash 組み込みコマンド <code>:</code> が一番速いと思われる。
 +
* <code>test</code> コマンドに文字列を渡す (-n オプションは省略可能なので、文字列が渡されると必ず真が返る。)
 +
* <code>true</code> コマンド
 +
* <code>:</code> コマンド
 +
 
 +
=== getopts ===
 +
こういう関数の使い方ってすぐ忘れるので、定型文化しておこう。
 +
GETOPT_ERR=0
 +
while getopts "i:nh" opt; do
 +
    case $opt in
 +
        i) INTERVAL=$OPTARG;;
 +
        n) NOPRINT=1;;
 +
        h) usage; exit 0;;
 +
        ?) GETOPT_ERR=1;;
 +
    esac
 +
done
 +
shift $(( $OPTIND - 1 ))
 +
 +
if [ $GETOPT_ERR -eq 1 ]; then
 +
    usage
 +
    exit 1
 +
fi
 +
 
 +
=== trap ===
 +
 
 +
テストスクリプトなどを書く場合のゴミ掃除には必須だが、毎回使い方を忘れるのでメモ。
 +
 
 +
* <code>ARG</code> が無い or <code>'-'</code> の場合は、初期値にリセット。
 +
* <code>ARG</code> が空文字列 "" の場合は、そのシグナルを無視する。
 +
* <code>EXIT</code> は終了時、<code>RETURN</code> は関数や source の終了時。
 +
 
 +
== Tips ==
 +
 
 +
=== コマンド実行後に任意の処理を行う ===
 +
bash には PROMPT_COMMAND という環境変数があり、これに任意のコマンドをセットすると、
 +
コマンド実行後に自動的に実行される。
 +
 
 +
例えば date をセットすると、コマンドを実行した日時が出力されるようになる。
 +
 
 +
kuro:~ kaz$ PROMPT_COMMAND=date
 +
2009年 6月12日 金曜日 01時41分46秒 JST
 +
kuro:~ kaz$ ls
 +
Desktop  Documents Downloads Library  Movies    Music    Pictures  Public    Sites
 +
2009年 6月12日 金曜日 01時41分50秒 JST
 +
 
 +
追記:<br>
 +
これ変数の名前から考えたら、コマンド実行後に実行されるんじゃなくて、
 +
プロンプト表示前に実行されるんですな。結果はどちらでも同じだけど。
 +
 
 +
==== コマンドの終了ステータスを自動的に表示する ====
 +
上記 PROMPT_COMMAND を使用して、コマンドがエラーで終了した場合などに終了ステータスを自動的に表示するようにする。
 +
終了ステータスはコマンド実行直後に表示しないと次のコマンド実行により上書きされてしまうため、
 +
うっかり操作により見逃してしまうことがあるが、自動的に表示することでこれを避けることができる。
 +
 
 +
~/.bashrc に以下を追加する。
 +
function prompt_cmd {
 +
    local ret=$?
 +
    [ $ret -eq 0 ] || echo "exit $ret"
 +
}
 +
PROMPT_COMMAND="prompt_cmd; $PROMPT_COMMAND"
 +
 
 +
実行結果のサンプル:
 +
 
 +
$ echo hoge
 +
hoge
 +
$ cat hoge
 +
cat: hoge: そのようなファイルやディレクトリはありません
 +
exit 1
 +
$ hoge
 +
bash: hoge: command not found
 +
exit 127
 +
 
 +
=== プロンプトに色を付ける ===
 +
コマンドの出力の境界がわかりやすくなったり、
 +
root になっているかどうかを色で判別できたり、かなり便利なこの機能。
 +
 
 +
.bashrc に以下を追記する。
 +
if [ -n "$PS1" ] ; then
 +
    col="0;33" # yellow
 +
    PS1="\[\033[${col}m\][\u@\h \W]$ \[\033[0m\]"
 +
          ^^^^^^^      ^^^            ^^^^^^^^^^^
 +
      色のエスケープシーケンス    色の設定をクリア
 +
fi
 +
 
 +
※当初、\e で書いていたが、カーソル位置と表示がズレる問題が発生したので修正した。
 +
 
 +
カラーリスト
 +
Black      0;30    Dark Gray    1;30
 +
Blue        0;34    Light Blue    1;34
 +
Green      0;32    Light Green  1;32
 +
Cyan        0;36    Light Cyan    1;36
 +
Red        0;31    Light Red    1;31
 +
Purple      0;35    Light Purple  1;35
 +
Brown      0;33    Yellow        1;33
 +
Light Gray  0;37    White        1;37
 +
 
 +
* [http://linuxjf.sourceforge.jp/JFdocs/Bash-Prompt-HOWTO-5.html Bash Prompt HOWTO: ANSI エスケープシーケンス: 色とカーソル操作]
 +
 
 +
=== ある数を n ビットシフトした数 ===
 +
カーネルソースを読んでいると、<code>512 << 16</code> などという数値が出てくることがあるが、
 +
わざわざ計算機を持ち出さなくても、bash で計算できる。
 +
$ echo $((512 << 16))
 +
33554432
 +
bash で計算できるということは、vi を使っていても、終了せずに計算できる。
 +
:!echo $((512 << 16))
 +
33554432
 +
 
 +
=== 直前にいたディレクトリに戻る ===
 +
<code>OLDPWD</code> 環境変数には、直前にいたディレクトリが格納されているので、
 +
$ cd $OLDPWD
 +
で戻ることができるが、cd に - を渡しても同様の結果となる。
 +
$ cd -
 +
深いディレクトリにいて、いったんホームディレクトリに行って帰ってくる場合などに便利だ。
 +
 
 +
== よく使うコマンド ==
 +
* 行頭にジャンプ:C-a 行末にジャンプ:C-e
 +
* 行頭までキル:C-u  行末までキル:C-k
 
* 前単語をキル:C-w
 
* 前単語をキル:C-w
 
* ヤンク:C-y
 
* ヤンク:C-y
行18: 行173:
 
* 前方検索:C-s
 
* 前方検索:C-s
 
* 最終行へ:M-> (Poderosa では打ちにくい…)
 
* 最終行へ:M-> (Poderosa では打ちにくい…)
 
== .bashrc ==
 
カスタマイズしたものに慣れてしまうと、素の状態にすぐに適応できなくなってしまうので良くないが、
 
それでも背に腹は代えられないモノたち。
 
alias ..='cd ..'
 
alias la='ls -a'
 
alias ll='ls -l' # Red Hat では標準
 
alias lla='ls -la'
 
alias llh='ls -lh'
 
alias s='screen'
 
alias grep='grep -i --color=auto'
 
 
# 自動 ls
 
function cd { builtin cd $@; ls }
 
# Ctrl-s でのストップ機能を止める
 
stty stop undef
 
 
  
 
== 起動時の設定ファイルの読み込み順序 ==
 
== 起動時の設定ファイルの読み込み順序 ==
 +
 
* ログインシェルの場合 (ログイン時、su - user 時など)
 
* ログインシェルの場合 (ログイン時、su - user 時など)
 
*# <code>/etc/profile</code>
 
*# <code>/etc/profile</code>
*# <code>/etc/profile.d/*.sh</code>
+
*#* 最後に <code>/etc/profile.d/*.sh</code>
 
*# <code>~/.bash_profile</code>
 
*# <code>~/.bash_profile</code>
*# <code>~/.bashrc</code>
+
*#* 最初に <code>~/.bashrc</code>
*# <code>/etc/bashrc</code>
+
*#** 最初に <code>/etc/bashrc</code>
 +
よって、記載順にもよるが、設定順は以下の通り。
 +
/etc/profile -> /etc/profile.d/*.sh -> /etc/bashrc -> ~/.bashrc -> ~/.bash_profile
 +
 
 
* ログインシェルでない場合 (bash 実行時、su user 時など)
 
* ログインシェルでない場合 (bash 実行時、su user 時など)
 
*# <code>~/.bashrc</code>
 
*# <code>~/.bashrc</code>
*# <code>/etc/bashrc</code>
+
*#* 最初に <code>/etc/bashrc</code>
*# <code>/etc/profile.d/*.sh</code>
+
*#** 最後に <code>/etc/profile.d/*.sh</code>
以下のコマンドで確認できる。
+
よって、記載順にもよるが、設定順は以下の通り。
 +
/etc/bashrc -> /etc/profile.d/*.sh -> ~/.bashrc
 +
 
 +
su 実行時に open() されるファイルは以下のコマンドで確認できる。
 
  # strace -f -e trace=open -o su-bash.strace su - hagio
 
  # strace -f -e trace=open -o su-bash.strace su - hagio
 +
 +
== その他 (細かいこと) ==
 +
* <code>export</code> は、その変数を子プロセスに引き継ぐ場合に用いる。
 +
# cat test.sh
 +
echo $TEST
 +
# sh test.sh
 +
 +
# TEST=hoge
 +
# sh test.sh
 +
 +
# TEST=hoge sh test.sh
 +
hoge
 +
# export TEST
 +
# sh test.sh
 +
hoge
 +
 +
一度 export された変数は、値を書き換えても export されたままなので、
 +
LANG などはその都度 export しなくても、実行するコマンドに渡される。
 +
 +
* Meta キーは、ESC キーあるいは Ctrl-[ で代用可。(Poderosa では有用)
 +
* bash のビルトインコマンドの説明を見るには、help コマンドが良い。man だと検索が面倒。
 +
 +
== My .bashrc ==
 +
カスタマイズしたものに慣れてしまうと、素の状態にすぐに適応できなくなってしまうので良くないが、
 +
それでも背に腹は代えられないモノたち。
 +
 +
# .bashrc
 +
 +
# Source global definitions
 +
if [ -f /etc/bashrc ]; then
 +
    . /etc/bashrc
 +
fi
 +
 +
# User specific aliases and functions
 +
umask 022
 +
 +
HISTSIZE=10000
 +
HISTFILESIZE=10000
 +
 +
function prompt_cmd {
 +
    local ret=$?
 +
    <nowiki>[[ $ret -eq 0 ]]</nowiki> || echo "exit $ret"
 +
}
 +
 +
if <nowiki>[[ $PS1 ]]</nowiki>; then
 +
    col=33
 +
    PS1="\[\033[${col}m\][\u@\h \W]$ \[\033[0m\]"
 +
 
 +
    alias C='LANG=C'
 +
    alias J='LANG=ja_JP.UTF-8'
 +
 
 +
    alias ..='cd ..'
 +
    alias la='ls -a'
 +
    alias lla='ls -la'
 +
    alias llh='ls -lh'
 +
 
 +
    alias c39='ssh 192.168.8.39'
 +
    alias c47='ssh 192.168.8.47'
 +
    alias c52='ssh 192.168.8.52'
 +
    alias s10='ssh 192.168.8.103'
 +
    alias s11='ssh 192.168.8.111'
 +
    alias r60='ssh 192.168.8.60'
 +
 +
    alias l='less'
 +
    alias c='cat'
 +
    alias ?='echo exit $?'
 +
 +
    complete -d cd
 +
    complete -c man
 +
 +
    export GREP_COLOR='1;37;44'
 +
    alias g='grep --color=auto'
 +
    alias gr='g -r'
 +
    alias gi='g -i'
 +
    alias pg='pgrep -lf'
 +
    alias xgr='find . | xargs -P 4 grep --color=auto'
 +
 +
    alias odx='od -Ax -tx1z'
 +
 +
    #PROMPT_COMMAND="prompt_cmd; $PROMPT_COMMAND"
 +
    function edit {
 +
        vi $(which "$1")
 +
    }
 +
fi

2023年10月11日 (水) 16:58時点における最新版

参考文献

シェルスクリプト

  • $# - 引数の個数なので、スクリプト名は含まない。(要は最後のインデックス)
  • BASH Programming - Introduction HOW-TO
  • $'string' の形式で特殊文字を出力できる。$'\x30' = '0' など。
  • $(cat file) とするなら、$(< file) の方が fork しないので速い。

配列

迷宮入りするかと思うほど理解するのが難しかった。。

  • 初期化 array=(hoge fuga piyo)
    • インデックス指定 array=([2]=piyo [0]=hoge [1]=fuga) は↑と同じ配列。
  • 参照 ${array[1]}
  • 要素数 ${#array[@]}

コマンド実行結果を 1 行ごとに配列に格納する

区切り文字を改行にしておかなければ、1 行ごとに格納されない。

IFS=$'\n'
array=( $( ls -l ) )

配列に要素を追加

これもハマった…。一旦展開するのがポイント。

array=( "${array[@]}" "hoge" )

パラメータ展開

スクリプトを書く際には便利なものの、忘れがちなので書いておく。

${parameter#pattern}   前方最短一致部分を削除
${parameter##pattern}  前方最長一致部分を削除
${parameter%pattern}   後方最短一致部分を削除
${parameter%%pattern}  後方最長一致部分を削除

わかりにくいので使用例を示す。

  • コマンドのパスから、そのコマンドがあるディレクトリのパスを得る
$ CMD_PATH=/usr/local/bin/hoge
$ echo ${CMD_PATH%/*}
/usr/local/bin
  • ファイル名から、拡張子だけを取り出す
$ FILE_NAME=hoge-1.2.txt
$ echo ${FILE_NAME##*.}
txt

無限ループ

こいつで 1 セクション作るのはどうかと思うが…、他に見出しを付ける方法がないので。

while :
do
  command
done

while に真を渡す方法はいくつかあるが、bash 組み込みコマンド : が一番速いと思われる。

  • test コマンドに文字列を渡す (-n オプションは省略可能なので、文字列が渡されると必ず真が返る。)
  • true コマンド
  • : コマンド

getopts

こういう関数の使い方ってすぐ忘れるので、定型文化しておこう。

GETOPT_ERR=0
while getopts "i:nh" opt; do
    case $opt in
        i) INTERVAL=$OPTARG;;
        n) NOPRINT=1;;
        h) usage; exit 0;;
        ?) GETOPT_ERR=1;;
    esac
done
shift $(( $OPTIND - 1 ))

if [ $GETOPT_ERR -eq 1 ]; then
    usage
    exit 1
fi

trap

テストスクリプトなどを書く場合のゴミ掃除には必須だが、毎回使い方を忘れるのでメモ。

  • ARG が無い or '-' の場合は、初期値にリセット。
  • ARG が空文字列 "" の場合は、そのシグナルを無視する。
  • EXIT は終了時、RETURN は関数や source の終了時。

Tips

コマンド実行後に任意の処理を行う

bash には PROMPT_COMMAND という環境変数があり、これに任意のコマンドをセットすると、 コマンド実行後に自動的に実行される。

例えば date をセットすると、コマンドを実行した日時が出力されるようになる。

kuro:~ kaz$ PROMPT_COMMAND=date
2009年 6月12日 金曜日 01時41分46秒 JST
kuro:~ kaz$ ls
Desktop   Documents Downloads Library   Movies    Music     Pictures  Public    Sites
2009年 6月12日 金曜日 01時41分50秒 JST

追記:
これ変数の名前から考えたら、コマンド実行後に実行されるんじゃなくて、 プロンプト表示前に実行されるんですな。結果はどちらでも同じだけど。

コマンドの終了ステータスを自動的に表示する

上記 PROMPT_COMMAND を使用して、コマンドがエラーで終了した場合などに終了ステータスを自動的に表示するようにする。 終了ステータスはコマンド実行直後に表示しないと次のコマンド実行により上書きされてしまうため、 うっかり操作により見逃してしまうことがあるが、自動的に表示することでこれを避けることができる。

~/.bashrc に以下を追加する。

function prompt_cmd {
    local ret=$?
    [ $ret -eq 0 ] || echo "exit $ret"
}
PROMPT_COMMAND="prompt_cmd; $PROMPT_COMMAND"

実行結果のサンプル:

$ echo hoge
hoge
$ cat hoge
cat: hoge: そのようなファイルやディレクトリはありません
exit 1
$ hoge
bash: hoge: command not found
exit 127

プロンプトに色を付ける

コマンドの出力の境界がわかりやすくなったり、 root になっているかどうかを色で判別できたり、かなり便利なこの機能。

.bashrc に以下を追記する。

if [ -n "$PS1" ] ; then
    col="0;33" # yellow
    PS1="\[\033[${col}m\][\u@\h \W]$ \[\033[0m\]"
         ^^^^^^^      ^^^            ^^^^^^^^^^^
     色のエスケープシーケンス     色の設定をクリア
fi

※当初、\e で書いていたが、カーソル位置と表示がズレる問題が発生したので修正した。

カラーリスト

Black       0;30     Dark Gray     1;30
Blue        0;34     Light Blue    1;34
Green       0;32     Light Green   1;32
Cyan        0;36     Light Cyan    1;36
Red         0;31     Light Red     1;31
Purple      0;35     Light Purple  1;35
Brown       0;33     Yellow        1;33
Light Gray  0;37     White         1;37

ある数を n ビットシフトした数

カーネルソースを読んでいると、512 << 16 などという数値が出てくることがあるが、 わざわざ計算機を持ち出さなくても、bash で計算できる。

$ echo $((512 << 16))
33554432

bash で計算できるということは、vi を使っていても、終了せずに計算できる。

:!echo $((512 << 16))
33554432

直前にいたディレクトリに戻る

OLDPWD 環境変数には、直前にいたディレクトリが格納されているので、

$ cd $OLDPWD

で戻ることができるが、cd に - を渡しても同様の結果となる。

$ cd -

深いディレクトリにいて、いったんホームディレクトリに行って帰ってくる場合などに便利だ。

よく使うコマンド

  • 行頭にジャンプ:C-a 行末にジャンプ:C-e
  • 行頭までキル:C-u  行末までキル:C-k
  • 前単語をキル:C-w
  • ヤンク:C-y
  • 直前のコマンドの最後の引き数を挿入:M-. (これは便利)
  • キャンセル:C-g
  • 後方検索:C-r (これらは使い方が難しい)
  • 前方検索:C-s
  • 最終行へ:M-> (Poderosa では打ちにくい…)

起動時の設定ファイルの読み込み順序

  • ログインシェルの場合 (ログイン時、su - user 時など)
    1. /etc/profile
      • 最後に /etc/profile.d/*.sh
    2. ~/.bash_profile
      • 最初に ~/.bashrc
        • 最初に /etc/bashrc

よって、記載順にもよるが、設定順は以下の通り。

/etc/profile -> /etc/profile.d/*.sh -> /etc/bashrc -> ~/.bashrc -> ~/.bash_profile
  • ログインシェルでない場合 (bash 実行時、su user 時など)
    1. ~/.bashrc
      • 最初に /etc/bashrc
        • 最後に /etc/profile.d/*.sh

よって、記載順にもよるが、設定順は以下の通り。

/etc/bashrc -> /etc/profile.d/*.sh -> ~/.bashrc

su 実行時に open() されるファイルは以下のコマンドで確認できる。

# strace -f -e trace=open -o su-bash.strace su - hagio

その他 (細かいこと)

  • export は、その変数を子プロセスに引き継ぐ場合に用いる。
# cat test.sh 
echo $TEST
# sh test.sh 

# TEST=hoge
# sh test.sh

# TEST=hoge sh test.sh
hoge
# export TEST
# sh test.sh
hoge

一度 export された変数は、値を書き換えても export されたままなので、 LANG などはその都度 export しなくても、実行するコマンドに渡される。

  • Meta キーは、ESC キーあるいは Ctrl-[ で代用可。(Poderosa では有用)
  • bash のビルトインコマンドの説明を見るには、help コマンドが良い。man だと検索が面倒。

My .bashrc

カスタマイズしたものに慣れてしまうと、素の状態にすぐに適応できなくなってしまうので良くないが、 それでも背に腹は代えられないモノたち。

# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
    . /etc/bashrc
fi

# User specific aliases and functions
umask 022

HISTSIZE=10000
HISTFILESIZE=10000

function prompt_cmd {
    local ret=$?
    [[ $ret -eq 0 ]] || echo "exit $ret"
}

if [[ $PS1 ]]; then
    col=33
    PS1="\[\033[${col}m\][\u@\h \W]$ \[\033[0m\]"
 
    alias C='LANG=C'
    alias J='LANG=ja_JP.UTF-8'
 
    alias ..='cd ..'
    alias la='ls -a'
    alias lla='ls -la'
    alias llh='ls -lh'
 
    alias c39='ssh 192.168.8.39'
    alias c47='ssh 192.168.8.47'
    alias c52='ssh 192.168.8.52'
    alias s10='ssh 192.168.8.103'
    alias s11='ssh 192.168.8.111'
    alias r60='ssh 192.168.8.60'

    alias l='less'
    alias c='cat'
    alias ?='echo exit $?'

    complete -d cd
    complete -c man

    export GREP_COLOR='1;37;44'
    alias g='grep --color=auto'
    alias gr='g -r'
    alias gi='g -i'
    alias pg='pgrep -lf'
    alias xgr='find . | xargs -P 4 grep --color=auto'

    alias odx='od -Ax -tx1z'

    #PROMPT_COMMAND="prompt_cmd; $PROMPT_COMMAND"
    function edit {
        vi $(which "$1")
    }
fi