bash のbrace 展開で文字列を置換する
文字の置換は、bashはとても楽ちんである。
NAME=www.example.com echo ${NAME//./_} # www_example.com echo ${NAME//./_} # www_example_com
これをもう少し掘り下げる。
bash でファイル名から拡張子を取出す方法
ファイル名から拡張子を取出すのはカンタンでした。
path=/etc/apache2/httpd.conf extension=${path##*.} #=> conf
魔法の記述方法 ${varname##*.}
を使うと 手軽に拡張子を取得できる。
拡張子を書き換える方法
拡張子を書き換えるには、変数の書き換えを使えば直ぐ出来る。
f_name=httpd.conf txt_name=${f_name/.*/.txt} #=> httpd.txt
basename / dirname の取得
basename や dirname も文字列マッチで行うことが出来る。
path=/etc/apache2/httpd.conf basename=${path##*/} #=> httpd.conf dirname=${path%/*} #=>/etc/apache2
拡張子だけを取り除く
path=/etc/apache2/httpd.conf basename=${path%.*} # /etc/apache2/httpd
仕組みについて
何でこんな不思議な事が出来るのか ${varname##*.}
のような記述方法は何のか。
http://linuxjm.osdn.jp/html/GNU_bash/man1/bash.1.html によると パラメータの展開 と呼ばれる機能だとわかった。
パラメータ展開について
bash には 変数の展開で、アレコレできるような機能が備わってる
記述方法 | 意味 |
---|---|
${parameter%word} | 後方マッチ削除 |
${parameter%%word} | 後方マッチ削除(最長マッチ) |
${parameter#word} | 前方マッチ削除 |
${parameter##word} | 前方マッチ削除(最長マッチ) |
${parameter/search/replacement} | マッチ置換 |
わかりにくいので、正規表現と対表作ってみる(bashはglobマッチなので厳密には一致しないがイメージとして覚えておくために)
記述方法 | 意味 |
---|---|
${parameter%%word} | parameter.replace( /(word)(.*)/ , '$1' ) |
${parameter##word} | parameter.replace( /(word)(.*)/ , '$2' ) |
${parameter/search/replacement} | parameter.replace( /word/ , replacement ) |
マッチの順番と考え方
パターンに依るパラメータ展開に目を通したので、冒頭の記号だらけの置換処理を見直してみる。
拡張子にマッチさせたときの bash の展開の流れ
最初の例の拡張子にマッチさせたときのbash展開の考え方について
path=/etc/apache2/httpd.conf extension=${path##*.} #=> conf
/etc/apache2/httpd.conf
場合/etc/apache2/httpd.conf
は *.とマッチさせる[ '/etc/apache2/httpd.' , 'conf']
に分割される- マッチした前方は消される
conf
が残る
basenameと同等の文字列マッチの場合の考え方
冒頭の basename を擬似的に文字列マッチで行った場合の例は
path=/etc/apache2/httpd.conf basename=${path##*/} #=> httpd.conf
/etc/apache2/httpd.conf
場合/etc/apache2/httpd.conf
を*/
と先頭から最長マッチさせる[ '/etc/apache2/' , 'httpd.conf']
に分割される- マッチした前方は消される
httpd.conf
が残る
次と同等になる。
'/etc/apache2/httpd.conf'.replace(/(^.*\/)(.*)/,'$2')
dirnameと同等の文字列マッチの場合の考え方
冒頭のdirnameと同等の文字列マッチの考え方。
path=/etc/apache2/httpd.conf dirname=${path%/*} echo $dirname #=>/etc/apache2
/etc/apache2/httpd.conf
場合/etc/apache2/httpd.conf
を/*
と末尾からマッチさせる/httpd.confがマッチする
[ '/etc/apache2' , '/httpd.conf']
に分割される- マッチした後方は消される
/etc/apache2
が残る
次と同等になる。
'/etc/apache2/httpd.conf'.replace(/(^.*\/)(.*)/,'$1')
変数展開で文字列を分割する
これらは、パスやファイル名の扱いというよりは、bash変数の文字列から部分文字列を取出す基本セットです。
man によると他にも
記述方法 | 意味 |
---|---|
${parameter:offset} | 部分文字列 ( 開始位置 ) |
${parameter:offset:length} | 部分文字列(開始位置から指定長) |
${#parameter} | 文字列長取得 |
他にどんなときに使えば便利?
今回はパスだったけど、起動オプションの引数や、PATH変数の操作などにも使えて便利ですね
sed 使わずに文字列置換できるのは本当に助かる