業務中にメモ帳やエクセルで特定の言葉や名称だけを変更したいときに「置き換え」機能を使ったことありませんか?
普段何気なく使っている便利な機能を、シェルスクリプトではどうやっているのかスクリプトを見ていきましょう。
置換する方法
シェルスクリプトの置換方法は「bash置換」と「sed置換」があります。
そして、文字列に対して置換を行う場合は、検索パターンと置換後の文字列を指定する必要があります。bash置換では、検索して見つかったパターンのうち最初だけ置換する方法と、見つかったパターン全てを置換する方法とがあります。sed置換は変数内の文字列を置き換えたい場合に使用します。
bash置換の書式
変数に対して、削除するパターンを指定します。前方・後方からの検索があり、最短マッチと最長マッチで動作が変わります。また、bash内で変数内の文字列を置換したり、変数に代入されたファイルパスからファイル名を取り出すことができます。
前方一致(文字列削除)
変数に代入された文字列から、後方一致でマッチしたパターン部分を削除します。
コマンドの書式
${変数名#パターン}(※1)
${変数名##パターン}(※2)
※1:前方からの検索一致で、一番初めにマッチした部分を削除します。
※2:前方からの検索一致で、一番後ろまでマッチした部分までを削除します。
# 前方からの検索一致で、一番初めにマッチした部分を削除
$ path=/usr/system1/system2/system.txt
$ echo ${path#*/}
# 前方からの検索一致で、一番後ろまでマッチした部分までを削除
$ path=/usr/system1/system2/system.txt
$ echo ${path##*/}
1 2 3 4 5 |
[root@CentOS7 bin]# path=/usr/system1/system2/system.txt [root@CentOS7 bin]# echo ${path#*/} usr/system1/system2/system.txt [root@CentOS7 bin]# echo ${path##*/} system.txt |
前方一致のパターンマッチングは、主にファイル名だけを抜き出す or ディレクトリ名だけを抜き出す等、ファイル・ディレクトリの操作で使用する機会が非常に多いコマンドです。
後方一致(文字列削除)
変数に代入された文字列から、後方一致でマッチしたパターン部分を削除します。
コマンドの書式
${変数名%パターン}(※1)
${変数名%%パターン} (※2)
※1:後方からの検索一致で、一番初めにマッチした部分までを削除します。
※2:後方からの検索一致で、一番後ろまでマッチした部分までを削除します。
# 後方からの検索一致で、一番初めにマッチした部分までを削除
$ path=/usr/system1/system2/system.txt.yyyymmdd
$ echo ${path%.*}
# 後方からの検索一致で、一番後ろまでマッチした部分までを削除
$ path=/usr/system1/system2/system.txt.yyyymmdd
$ echo ${path%%.*}
後方一致のパターンマッチングは、主にファイル名の操作で使用する機会が非常に多いコマンドです。
1 2 3 4 5 6 |
[root@CentOS7 bin]# path=/usr/system1/system2/system.txt.yyyymmdd [root@CentOS7 bin]# echo ${path%.*} /usr/system1/system2/system.txt [root@CentOS7 bin]# echo ${path%%.*} /usr/system1/system2/system [root@CentOS7 bin]# |
文字列置換
文字列置換は、一番初めにマッチした部分だけを置換する部分置換と、一番後ろまでマッチした部分(すべて)を置換する全置換の2種類があります。いずれも検索パターンと置換文字を指定して使用します。
コマンドの書式
${変数名/パターン/置換}(※1)
${変数名//パターン/置換}(※2)
※1:一番初めにマッチしたパターン部分を置換します。
※2:マッチしたすべてのパターンを置換します。
最初にマッチしたもののみ文字列を置換
# 一番初めにマッチした部分を置換
$ path=/usr/system1/system2/system.txt
$ echo ${path/system/------}
# マッチしたすべてのパターンを置換
$ path=/usr/system1/system2/system.txt
$ echo ${path//system/------}
1 2 3 4 5 6 |
[root@CentOS7 bin]# path=/usr/system1/system2/system.txt [root@CentOS7 bin]# echo ${path/system/------} /usr/------1/system2/system.txt [root@CentOS7 bin]# echo ${path//system/------} /usr/------1/------2/------.txt [root@CentOS7 bin]# |
sed置換の書式
「sed」コマンドは、引数で指定したファイルに対し、指定した置換パターンでの処理を施し、その結果を標準出力に出力します。
sedで文字列を置換する
「sed」は指定したファイルの文字列を決まった書式に従って文字列を置換して表示するコマンドです。文字列を置き換えるには、以下の書式で記述します。
コマンドの書式
sed -e “s/置換前/置換後/g” ファイル名
「s/置換条件/置換条件/g」にすることで、入力された文字列内で置換条件に合致する文字列を全て置換することが出来ます。
コマンドの主なオプション
- -r( --regexp-extended ): スクリプトで拡張正規表現を使用する
- -e( --expression=スクリプト ): スクリプト(コマンド)を追加する
- -i( --in-place ): ファイルを直接編集する
- -n( --quiet,--silent ): 出力コマンド以外の出力を行わない
- -l( --line-length=文字数 ): lコマンドの出力行を折り返す長さを指定する
- -z( --null-data ): NUL文字で行を分割する(通常は改行で分割)
実際に実行してみます。ここでは、コンソールの変数に格納されたファイル名「abc.txt」を「abc.doc」へ置換してみます。「echo」コマンドで出力されたファイル名(置換対象)を「|(パイプ)」でつないだ「sed」コマンドで処理します。
# ファイル名「abc.txt」を「abc.doc」へ置換する
$ check="abc.txt"
$ echo ${check} | sed -e "s/\.txt/.doc/"
※ 置換されるのは、コンソール上へ出力されるファイル名です。実ファイル名を変更することはありません。
1 2 3 |
[root@CentOS7 bin]# check="abc.txt" [root@CentOS7 bin]# echo $check | sed -e "s/\.txt/.doc/" abc.doc |
ココに注意
置換条件ではドット「.」は任意の1文字の意味を持ってしまうので、ドット自身を表示したい場合は「\.」と記述しましょう。(これをエスケープ処理と呼びます。)
正規表現
sedでは置換する文字列を探す場合に正規表現が利用できます。
ちなみに、正規表現というのは1文字や行末といった条件を記号で表記して複雑なパターンを指定できる表記方法のことを言います。主な正規表現を下記にまとめてみました。
メタ文字 | 意味 |
---|---|
. | 改行文字以外の任意の1文字 |
* | 直前の1文字の0回以上の繰り返しに一致 |
^ | 行の先頭 |
$ | 行の末尾 |
[ ] | かっこ内の任意の1文字に一致。 ハイフン(-)で範囲指定も可能 |
[^ ] | かっこ内の任意の1文字に不一致。 ハイフン(-)で範囲指定可能 |
\+ | 直前の文字の1個以上の繰り返しに一致 |
\? | 直前の文字の0または1文字に一致 |
\{n\} | 直前の文字のn個の繰り返しに一致 |
\{n,\} | 直前の文字のn個以上の繰り返しに一致 |
\{,n\} | 直前の文字のn個以下の繰り返しに一致 |
\{n,m\} | 直前の文字のn個以上,m個以下の繰り返しに一致 |
パターン1\|パターン2 | パターン1またはパターン2のいずれかに一致 |
\(パターン\) | パターンをグループ化する。 マッチした内容は\1や\2として使用可能 |
\(エスケープ) | 正規表現に使われる記号を普通の文字として扱いたい時使用する |
sedで特定文字列を削除して表示する
設定ファイルや定義ファイル等を編集しているとき、自動で特定の文字(コメント行)等を全て削除して表示したいと思ったことありませんか?sedを使って、テキストファイルの中身を操作することが出来ます。
コマンドの書式
sed -e '/文字列/d' ファイル名
実際の設定ファイルですと数百行に及ぶことが普通です。コンソール上へ表示してもコメント行ばかりで肝心の設定値はわずか数行しかないなんて場合がほとんどです。うざいですよね?
そんな時は、特定の文字列から始まる行(#コメント行など)を削除して表示してしまえば良いのです。例えば下記のようなファイルです。
test.conf
# コメント行
command 1
# コメント行
command 2
command 3
# コメント行
command 4
command 5
command 6
# コメント行
command 7
command 8
command 9
ファイル「test.conf」から、先頭が「#(コメント)」で始まる行だけ削除して表示します。
# 特定の文字を含む行を削除する
$ sed -e "/\#/d" test.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
[root@CentOS7 bin]# cat test.conf 👈 「test.conf」の中身を表示 # コメント行 command 1 # コメント行 command 2 command 3 # コメント行 command 4 command 5 command 6 # コメント行 command 7 command 8 command 9 [root@CentOS7 bin]# sed -e "/\#/d" test.conf 👈 コメントを消して表示 command 1 command 2 command 3 command 4 command 5 command 6 command 7 command 8 command 9 [root@CentOS7 bin]# |
すっきりしまいた!
※ 対象文字列「#(コメント)」から始まる行が削除されて表示されていますが、「test.conf」の中身は変更されません。
もし、ファイル「test.conf」の中身も変更してしまいたい場合は、対象文字列「#(コメント)」から始まる行を削除して、新しいファイル「new_test.conf」へ出力します。
# 対象文字列「#(コメント)」から始まる行を削除して、新しいファイルへ出力
$ sed -e "/^#/d" test.conf > new_test.conf
対象文字列「#(コメント)」から始まる行を削除して、新しいファイル「new_test.conf」へ出力されました。
1 2 3 4 5 6 7 8 9 10 11 |
[root@CentOS7 bin]# sed -e "/^#/d" test.conf > new_test.conf [root@CentOS7 bin]# cat new_test.conf command 1 command 2 command 3 command 4 command 5 command 6 command 7 command 8 command 9 |
使いどころとしては、単体テストなどでのエビデンス取得に使えるコマンドかもしれません。
Shellスクリプト基礎知識(全11記事+1)
├─シェルスクリプトの基本事項!
├─変数と特殊変数について!
├─演算子「算術演算子」「比較演算子」について!
├─条件分岐「if」「case」について!
├─ループ処理「for」「while」について!
├─文字列置換「bash」「sed」について!
├─複数行のテキスト出力!ヒアドキュメントについて!
├─書式?戻り値?シェルスクリプト内の関数について!
├─シェルの組み込みコマンドについて!
├─クォートとは?コマンド置換とは?実現方法と内容の違いについて!
└─リダイレクトとは?標準入力・出力、標準エラー出力等について!
(補足)シェルスクリプトの設計書とは?必要な項目や書き方等を解説!