Shellスクリプトは、システム管理やデータ処理において強力なツールです。
その中でも文字列置換は非常に頻繁に使用される操作の一つです。本記事では、BashとSedを活用した文字列置換の基本について詳しく解説します。
初心者の方でも分かりやすいように、基本的な構文や実用例を交えながら進めていきます。
Shellの基礎知識 🟡 Shell の基礎知識(入門編) 🟡 Shell の基礎知識(基礎編) 🟡 Shell の基礎知識(実践編)
📌 「動かす楽しさ」を最短で体感!Shellの第一歩をここから。
📌 条件分岐やループなど、実務で通用する基本操作を網羅。
├─【Shellの基礎知識】Shellスクリプト入門|初心者が押さえる基本
├─【Shellの基礎知識】変数と特殊変数の使い方|初心者向け解説
├─【Shellの基礎知識】Shell演算子の完全ガイド|基礎から応用まで
├─【Shellの基礎知識】条件分岐『if』『case』の使い方を解説
├─【Shellの基礎知識】ループ処理の基本|効率化と応用例を解説
├─【Shellの基礎知識】文字列置換の基本と応用|初心者向け解説
├─【Shellの基礎知識】複数行テキスト出力を簡単に!ヒアドキュメント活用法
├─【Shellの基礎知識】関数の基本と応用|書式と戻り値を解説
├─【Shellの基礎知識】組み込みコマンドの活用法|最適化テクニック
├─【Shellの基礎知識】クォートとコマンド置換の違いと使い分け
└─【Shellの基礎知識】リダイレクトの基本|標準入出力とエラー出力
📌 現場レベルの自動化スクリプトを実装しながら学ぶ実戦形式。
文字列置換の重要性と基本概念
文字列置換は、テキストデータを効率的に操作するために不可欠な技術です。例えば、システム管理者がログファイルの特定のパターンを検索して別の文字列に置き換える場合や、大量のデータを一括編集する際に活用されます。以下に具体例を示します。
文字列置換の実践例
文字列置換は、システム管理やデータ処理の現場で非常に有用なスキルです。このセクションでは、Shellスクリプトを使用して効率的に文字列を置換する具体的な手法を紹介します。以下に、ログファイルの編集やファイル名の変更を例に挙げ、それぞれの手順と結果を詳しく説明します。
例1: 特定のIPアドレスを匿名化する例
この例では、server.log ファイルに記録された特定のIPアドレス(例: 192.168.1.1)を匿名化し、プライバシーを保護します。sed コマンドを使用して、IPアドレスを "ANONYMIZED_IP" に置き換え、その結果を新しいファイル updated_server.log に保存します。
この操作により、元のログファイルはそのまま保持され、匿名化された内容を別のファイルとして利用することができます。
元ファイル:server.log
192.168.1.1 - - [12/Jan/2025:10:00:00 +0900] "GET /index.html HTTP/1.1" 200 1024
10.0.0.1 - - [12/Jan/2025:10:01:00 +0900] "POST /form.html HTTP/1.1" 404 512
192.168.1.1 - - [12/Jan/2025:10:02:00 +0900] "GET /about.html HTTP/1.1" 200 2048
sed 's/192.168.1.1/ANONYMIZED_IP/g' server.log > updated_server.log
コマンド実行後に作成されるファイル:updated_server.log
ANONYMIZED_IP - - [12/Jan/2025:10:00:00 +0900] "GET /index.html HTTP/1.1" 200 1024
10.0.0.1 - - [12/Jan/2025:10:01:00 +0900] "POST /form.html HTTP/1.1" 404 512
ANONYMIZED_IP - - [12/Jan/2025:10:02:00 +0900] "GET /about.html HTTP/1.1" 200 2048
このコマンドは、もともと作成されている server.log に対して特定のIPアドレスを "ANONYMIZED_IP" に匿名化し、その結果を updated_server.log に保存します。
(元の server.log ファイルを直接変更することはしません。)
これにより、指定されたIPアドレスがすべて "ANONYMIZED_IP" に置き換わります。
例2: ファイル名の一括変更
この例では、ファイル名に含まれる特定の文字列(例: "remove_this")を「_」に置き換えます。for ループと変数展開を活用し、ディレクトリ内の複数の .txt ファイル名を一括で変更します。
このスクリプトは、元のファイル名を新しいファイル名に置き換えます。
(元のファイルは削除されるため、必要に応じて事前にバックアップを作成してください。)
元ファイル:
sample_remove_this_file.txt
data_remove_this_record.txt
実行するコマンド:
for file in *.txt; do
mv "$file" "${file//remove_this/}"
done
実行後のファイル:
sample___file.txt
data___record.txt
このスクリプトは、ファイル名に含まれる文字列 "remove_this" を削除します。
これらの例からも分かるように、文字列置換は実務的な作業を効率化するための非常に強力な手段です。文字列置換は、プログラム内で文字やパターンを動的に変更するための重要なスキルです。
文字列置換の基礎
本セクションでは、シェルスクリプト初心者でも理解しやすいように、文字列置換の基本概念と活用方法を解説します。また、BashとSedという2つの主要なツールの違いと特徴についても触れ、どのような状況でこれらを使い分けるべきかを説明します。
文字列置換は、テキストやデータを効率的に操作するために非常に重要な技術です。BashとSedは、これを実現するための2つの強力なツールとして広く使用されています。
このセクションでは、BashとSedを活用した文字列置換の基本的な使い方を詳しく解説します。
Bashの基本的なテクニック
Bashを使った文字列置換では、いくつかの基本的なテクニックがあります。
Bashでは、コマンド置換を行う方法として「バックティックス『`』形式」と「$()形式」の2つがあります。ただし、$()形式はバックティックスとは異なり、モダンなコマンド置換の構文です。
バックティックスは古い形式で、可読性やネストのしやすさに劣るため、$()形式が推奨されます。また、文字列内の特殊文字をエスケープするためには、バックスラッシュを使用します。また、文字列置換では、パラメータ展開を利用することで柔軟な操作が可能です。
Bashの基本的なテクニック
- バックティックス置換:
コマンドの出力を文字列として取得し、再利用する手法です。たとえば、echo $(date) と記述することで現在の日時を取得できます。 - バックスラッシュ置換:
特殊文字をエスケープするために使用されます。たとえば、echo "Hello \"World\"" と記述することで、"World" を含む文字列を出力できます。 - パラメータ展開を使用した文字列置換:
- ${variable//pattern/replacement}: 変数内の文字列を指定のパターンで置き換えます。
- 例:filename="example_remove_this_file.txt"の場合
filename="example_remove_tihs_file.txt"
echo ${filename//remove_tins/_}
出力: example___file.txt
- 部分一致の切り取り:
- ${variable#substring}: 先頭から指定した文字列を削除します。
例:filepath="/home/user/documents/file.txt"
echo ${filepath#*/user/}
出力: documents/file.txt
- ${variable#substring}: 先頭から指定した文字列を削除します。
昨今では、スクリプトの可読性を高めるため、バックティックスの代わりに $()形式を使用することが推奨されます。
パラメータ展開:『#』と『%』 の違いについて
Bashでは、文字列置換においてパラメータ展開を活用することができます。
${variable#substring} は、変数の先頭から指定した文字列に一致する部分を削除する機能を提供します。一方で、${variable%substring} を使用すると、変数の末尾から一致する部分を削除することが可能です。
『#』と『%』の違い
- ${variable#substring}: 先頭一致の削除例:この例では、/user/ に一致する部分(/home/user/)が削除されます。
filepath="/home/user/documents/file.txt"
echo ${filepath#*/user/}
結果: documents/file.txt - ${variable%substring}: 末尾一致の削除 例:この例では、末尾のスラッシュ / 以降(file.txt)が削除されます。
filepath="/home/user/documents/file.txt"
echo ${filepath%/}
結果: /home/user/documents
これらは変数に対して、削除するパターンを指定します。前方・後方からの検索があり、最短マッチと最長マッチで動作が変わります。また、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 's/置換対象/置換後/' で、最初に一致したパターンのみを置換します。
一方、sed 's/置換対象/置換後/g' を使用すると、一致するすべてのパターンを置換します。例えば、次のコマンドは "hello world" を "hello universe" に置換します。
echo "hello world" | sed 's/world/universe/'
結果: hello universe
また、-i オプションを使用すると、ファイル内の文字列を直接編集することができます。例えば、次のコマンドはファイル内の文字列 "old" を "new" に置換します。
sed -i 's/old/new/g' example.txt
さらに、Sedでは正規表現を使用した高度な置換が可能です。次の例では、電話番号内の数字を "X" に置換します。
echo "123-456-7890" | sed 's/[0-9]/X/g'
結果: XXX-XXX-XXXX
sedで文字列を置換する
「sed」は指定したファイルの文字列を決まった書式に従って文字列を置換して表示するコマンドです。文字列を置き換えるには、以下の書式で記述します。
コマンドの書式
sed [ オプション ] “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で特定文字列を削除して表示する
設定ファイルや定義ファイル等を編集しているとき、自動で特定の文字(コメント行)等を全て削除して表示したいと思ったことありませんか?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 |
使いどころとしては、設定ファイルの表示に余計なコメント行を除いて設定値のみ表示させる場合などに効果を発揮します。
主な正規表現
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として使用可能 |
\(エスケープ) | 正規表現に使われる記号を普通の文字として扱いたい時使用する |
この記事を読んだら、次は 「【Shellの基礎知識】複数行テキスト出力を簡単に!ヒアドキュメント活用法」 を読むのがおすすめです!