Tech Blog

フィルタの使用法

2021-03-01

sedコマンド

標準入力からデータを受け取って編集後の結果を標準出力に書き出します。

cat samplefile
OldTextjahjsaOldTextajs
mmmnnnn
hasjhOldTexthajsh
sed -e "s/OldText/NewText/" samplefile
NewTextjahjsaOldTextajs
mmmnnnn
hasjhNewTexthajsh

結果を残す場合は、リダイレクトさせます。

sed -e "s/OldText/NewText/" samplefile > resultfile

sedにつけた-eというオプションは、その後の文字列が編集用のコマンドだということ を表します。

sは置き換え(substitute)の意味です。s/OldText/NewText/と書くことで、 2つの文字列の左側の文字を右側の文字に置き換えます。

1行の中で見つけた文字列を全て置き換える場合には s/OldText/NewText/gと指定します。

sed -e "s/OldText/NewText/g" samplefile
NewTextjahjsaNewTextajs
mmmnnnn
hasjhNewTexthajsh

-nコマンドは指示した行のみ実行するように指定できます。

sed -n '2p' < samplefile
mmmnnnn
sed -n '3p' < samplefile
hasjhOldTexthajsh

置き換えた行のみ表示する場合は以下のようになります。

sed -n -e "s/OldText/NewText/gp" samplefile
NewTextjahjsaNewTextajs
hasjhNewTexthajsh

sedコマンドをパイプでつなぐ

cat samplefile |
sed -e "s/OldText/Newtext/g" |
sed -e "s/mmm/MMM/g" |
while read LINE
do
echo $LINE
done

出力結果⏬

NewtextjahjsaNewtextajs
MMMnnnn
hasjhNewtexthajsh

sedコマンドのデリミタについて

sedコマンドのデリミタ/は変更可能です。

sの後の次の文字がデリミタとして認識される仕様となっており、 慣習的に/が使われますが、%@を使っても問題ありません。

cat samplefile |
sed -e "s%OldText%Newtext%g"
NewtextjahjsaNewtextajs
mmmnnnn
hasjhNewtexthajsh

sedコマンドでの編集について

文字列の変換

sed -e "s/OldText/NewText/g"

gがあれば、行の全てを対象(globallyの略)にします。

文字列の削除

sed -e "s/TextToRemove//g"

何もない文字列に返還させると文字列を結果的に削除できます。

行頭の文字列を消す

sed -e "s/^TextToRemove//"

行頭の文字が指定した文字列に一致すれば削除する例です。

行末の文字列を消す

sed -e "s/TextToRemove\$//"

文字列を追加する

sed -e "s/nnnn/nnnnAddText/" samplefile
OldTextjahjsaOldTextajs
mmmAddText
hasjhOldTexthajsh

nnnnという文字列の後にAddTextという文字を追加します。

行の先頭に文字列を追加する

sed -e "s/^/AddText/" samplefile
AddTextOldTextjahjsaOldTextajs
AddTextmmmnnnn
AddTexthasjhOldTexthajsh

行末に文字列を追加する

sed -e "s/\$/AddText/" samplefile
OldTextjahjsaOldTextajsAddText
mmmnnnnAddText
hasjhOldTexthajshAddText

ドットとアスタリスク

.には任意の1文字の意味があります。シェルの特殊文字?と似たような働きを持ちます。

sed -e "s/^...//" samplefile
TextjahjsaOldTextajs
nnnn
jhOldTexthajsh

行頭の3文字を削除しています。

*は直前の文字が任意の個数連続した場合(0も含む)を表します。

a*という指定は、a、aa、aaaaaなどaが任意の個数続く文字列を表します。

.*を指定すると、任意の文字列を表します。

sed -e "s/.*/abcd/" samplefile
abcd
abcd
abcd

.*は全ての文字列に当てはまるため、行を全て、abcdに置き換えます。

文字列の切り詰め、切り取り

以下のファイルがあるとします。

cat file
abcdefghijklmn
opqrstuvwxyz
0123456789
abc(defgh)aijkl
mn(op)qrstuvwxyz

e以降の5文字をABCに置き換えます。

sed -e "s/e...../ABC/" file
abcdABCklmn
opqrstuvwxyz
0123456789
abc(dABCijkl
mn(op)qrstuvwxyz

sを含めsより前の文字を切り取り

sed -e "s/.*s//" file
abcdefghijklmn
tuvwxyz
0123456789
abc(defgh)aijkl
tuvwxyz

全ての行をXYZに置き換えます。

sed -e "s/.*/XYZ/" file
XYZ
XYZ
XYZ
XYZ
XYZ

カッコの中の文字を全て消去

sed -e "s/(.*)/()/" file
abcdefghijklmn
opqrstuvwxyz
0123456789
abc()aijkl
mn()qrstuvwxyz

idコマンドから最初のuidを取り出す。

id | sed -e "s/uid=//" -e "s/(.*//"

idコマンドから最初のユーザー名を取り出す。

id | sed 's/uid=.*(\(.*\)) gid=.*/\1/'

\1は丸括弧で囲んだ部分を1つ目を取り出せる。

丸括弧は文字列として扱われないようにエスケープする。

ある文字の最初からn文字を切り取る

echo "$STRING" | cut -c1-5
#!/bin/sh
STRING=abcdefghijklmlopqrstuvwxyz
FIRST=1
LEN=5
echo $STRING | cut -c$FIRST-$LEN

行頭FIRST番目からLEN文字分を切り取ります。

awkコマンドで行頭の文字を切り取る

awk '{printf "%-.5s\n", $0}' < file
abcde
opqrs
01234
abc(d
mn(op

sedコマンドでは以下のようになります。

sed -e "s/^\(.....\).*/\1/" file
abcde
opqrs
01234
abc(d
mn(op

大文字と小文字を入れ替える

cat file | tr '[A-Z]' '[a-z]' > lowerfile
cat file
abcdefghijklmn
opqrstuvwxyz
0123456789
abc(defgh)aijkl
mn(op)qrstuvwxyz
cat file | tr '[a-z]' '[A-Z]'
ABCDEFGHIJKLMN
OPQRSTUVWXYZ
0123456789
ABC(DEFGH)AIJKL
MN(OP)QRSTUVWXYZ

アルファベットだけを変換し、数字やその他の文字は変換しません。

タブをスペースに変換

sed -e 's/<tab>/<space>/g'

複数のスペースを1個のスペースに変換

sed -e 's/<space><space>*/<space>/g'

ホワイトスペースを1個のスペースに変換

ホワイトスペースとはタブかスペースのことです。

タブやスペースが混在している場合に1個のスペースに変えるには以下のようにします。

sed -e 's/[<space><tab>][<space><tab>]*/<space>/g'

鉤括弧でどちらかを表現できます。

行頭のホワイトスペースを削除

sed -e 's/^[<space><tab>]*//'

行末のホワイトスペースを削除

sed -e 's/<space><tab>]*$//'

ダブルクォートで囲った場合は$をエスケープします。

sed -e "s/<space><tab>]*\$//"

文字列指定による行の削除

Testという文字列を削除する場合の例です。

sed -e "/Test/d"
cat samplefile
OldTextjahjsaOldTextajs
mmmnnnn
hasjhOldTexthajsh
sed -e '/OldText/d' samplefile
mmmnnnn

grep -vで該当する文字列を含んだ行を表示しないという意味になります。 そのため、以下でも同じことができます。

cat samplefile | grep -v "OldText"
mmmnnnn

sedによる行の指定

何行目から何行目までを編集するといった指定も可能です。 2から3行目を書き換える場合は以下のように記述します。

sed -e "2,3s/OldText/NewText/g" samplefile
OldTextjahjsaOldTextajs
mmmnnnn
hasjhNewTexthajsh

指定されていない行については何もしません。

行の削除

1行目を削除する場合は以下のように書けます。

sed -e '1d' samplefile
mmmnnnn
hasjhOldTexthajsh

最終行を削除する場合は以下です。

sed -e '$d' samplefile
OldTextjahjsaOldTextajs
mmmnnnn

指定した行だけを表示する

2行目から最終行までを表示しないようにするので、1行目を表示することになります。

1行目を表示する

sed -e '2,$d' samplefile
sed -n '1p' samplefile

最終行を表示する

sed -n '$p' samplefile

1行目から2行目を表示する

sed -n '1,2p' samplefile

コメント行の削除

以下のようなファイルがあるとして、

cat samplefile2
OldTextjahjsaOldTextajs
mmmnnnn # comment
# vvvvxxxx
hasjhOldTexthajsh

先頭に#がある行を削除したい場合は、以下となります。

sed -e '/^#/d' samplefile2
OldTextjahjsaOldTextajs
mmmnnnn # comment
hasjhOldTexthajsh

また、途中で#が出てくる行のコメントも削除したければ以下で良さそうです。

sed -e 's/#.*//' samplefile2 | sed -e '/^$/d'
OldTextjahjsaOldTextajs
mmmnnnn
hasjhOldTexthajsh

#以降の文字を空に置き換えます。

ただそれだけでは、# vvvvxxxxの行が空行として残ってしまうため、 空行を削除しています。

キーワードによる行の指定

cat fileaa
xxxxxxxxxxxxxxxxxxxxxx
Beginaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbb
cccccccccccccccccccccc
ddddddddddEndddddddddd
eeeeeeeeeeeeeeeeeeeeee

BeginとEndで囲まれた部分の行を表示するには、 行数指定すれば

sed -n '2,5p' fileaa

削除する場合は、

sed -e "2,5d" fileaa

と書けますが、 /StartingPattern/,/EndingPatternというパターンを使い、 キーワードを使った行指定も可能です。

sed -n "/Begin/,'End/p" fileaa
sed -e "/Begin/,/End/d" fileaa

また、キーワードがキーワードの行のみ

cat filebb
xxxxxxxxxxxxxxxxxxxxxx
Begin
aaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbb
cccccccccccccccccccccc
dddddddddd
End
ddddddddd
eeeeeeeeeeeeeeeeeeeeee

のようになっている場合は、

sed -n "/^Begin\$/,/^End\$/p" filebb

とすることで、もし意図しないところにキーワード(ここではBegin、End)がある場合にも 対応できるため確実です。

ファイルを後ろから表示する

cat filebb | grep -n '.*' | sort -n -r | sed 's/^[0-9]*://'

まず、grepコマンドに-nオプションを用いて、行番号をつけます。

その際に全ての文字列に一致する.*を指定して、全ての行を出力します。

cat filebb | grep -n '.*'
1:xxxxxxxxxxxxxxxxxxxxxx
2:Begin
3:aaaaaaaaaaaaaaaaa
4:bbbbbbbbbbbbbbbbbbbbbb
5:cccccccccccccccccccccc
6:dddddddddd
7:End
8:ddddddddd
9:eeeeeeeeeeeeeeeeeeeeee

sortコマンドで逆の番号順に並べます。

cat filebb | grep -n '.*' | sort -n -r
9:eeeeeeeeeeeeeeeeeeeeee
8:ddddddddd
7:End
6:dddddddddd
5:cccccccccccccccccccccc
4:bbbbbbbbbbbbbbbbbbbbbb
3:aaaaaaaaaaaaaaaaa
2:Begin
1:xxxxxxxxxxxxxxxxxxxxxx

最後に不要な番号とコロンを削除します。

cat filebb | grep -n '.*' | sort -n -r | sed 's/^[0-9]*://'
eeeeeeeeeeeeeeeeeeeeee
ddddddddd
End
dddddddddd
cccccccccccccccccccccc
bbbbbbbbbbbbbbbbbbbbbb
aaaaaaaaaaaaaaaaa
Begin
xxxxxxxxxxxxxxxxxxxxxx