はじめに
最近Linuxでコマンドの出力結果やファイルに文字列を追加したり削除する方法について説明する機会が多いので、備忘録も兼ねてコマンドの使い方を記載しておきます。
よく紹介されているsed
コマンド以外の方法も記載しているので、用途に合った方法を選んでもらえればと思います。
sed
コマンドの先頭行・末尾行の操作方法
sed
コマンドは文字列を置換をするコマンドとして有名ですが、文字列の追加や行の削除・抽出も行える非常に強力なコマンドです。
とりあえずsed
コマンドを知っていればコマンドの出力結果(標準出力)やファイルの行の操作は何とかなりますので、覚えておくことをオススメします。
・行を追加する(標準出力)
コマンドの実行結果(標準出力)のテキストの先頭行や末尾行に追加したい文字列の行を追加する方法です。
【コマンドの書き方】
(コマンド) | sed '1i(先頭行に追加する文字列)'
(コマンド) | sed '$a(末尾行に追加する文字列)'
(コマンド) | sed -e '1i(先頭行に追加する文字列)' -e '$a(末尾行に追加する文字列)'
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle
end
$
$ # 先頭行に文字列ADDを追加
$ cat hoge.txt | sed '1iADD'
ADD
top
middle
end
$
$ # 末尾行に文字列ADDを追加
$ cat hoge.txt | sed '$aADD'
top
middle
end
ADD
$
$ # 先頭行と末尾行に文字列ADDを追加
$ cat hoge.txt | sed -e '1iADD-TOP' -e '$aADD-END'
ADD-TOP
top
middle
end
ADD-END
$
・行を追加する(ファイル)
ファイルの先頭行や末尾行に追加したい文字列の行を追加する方法です。
【コマンドの書き方】
sed -i '1i(先頭行に追加する文字列)' (ファイルパス)
sed -i '$a(末尾行に追加する文字列)' (ファイルパス)
sed -i -e '1i(先頭行に追加する文字列)' -e '$a(末尾行に追加する文字列)' (ファイルパス)
【コマンドのサンプル】
$ # 先頭行に文字列ADDを追加
$ sed -i '1iADD' hoge.txt
$
$ # 末尾行に文字列ADDを追加
$ sed -i '$aADD' hoge.txt
$
$ # 先頭行と末尾行に文字列ADDを追加
$ sed -i -e '1iADD-TOP' -e '$aADD-END' hoge.txt
$
・行を削除する(標準出力)
コマンドの実行結果(標準出力)のテキストの先頭行や末尾行を削除する方法です。
【コマンドの書き方】
(コマンド) | sed '1d'
(コマンド) | sed '$d'
(コマンド) | sed -e '1d' -e '$d'
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle
end
$
$ # 先頭行を削除
$ cat hoge.txt | sed '1d'
middle
end
$
$ # 末尾行を削除
$ cat hoge.txt | sed '$d'
top
middle
$
$ # 先頭行と末尾行を削除
$ cat hoge.txt | sed -e '1d' -e '$d'
middle
$
・行を削除する(ファイル)
ファイルの先頭行や末尾行を削除する方法です。
【コマンドの書き方】
sed -i '1d' (ファイルパス)
sed -i '$d' (ファイルパス)
sed -i -e '1d' -e '$d' (ファイルパス)
【コマンドのサンプル】
$ # 先頭行を削除
$ sed -i '1d' hoge.txt
$
$ # 末尾行を削除
$ sed -i '$d' hoge.txt
$
$ # 先頭行と末尾行を削除
$ sed -i -e '1d' -e '$d' hoge.txt
$
・行を抽出する(標準出力)
コマンドの実行結果(標準出力)のテキストの先頭行や末尾行を表示(抽出)する方法です。
【コマンドの書き方】
(コマンド) | sed -n '1p'
(コマンド) | sed -n '$p'
(コマンド) | sed -n -e '1p' -e '$p'
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle
end
$
$ # 先頭行を抽出
$ cat hoge.txt | sed -n '1p'
top
$
$ # 末尾行を抽出
$ cat hoge.txt | sed -n '$p'
end
$
$ # 先頭行と末尾行を抽出
$ cat hoge.txt | sed -n -e '1p' -e '$p'
top
end
$
上記の方法で読み込むテキストが大きい場合は処理が完了するまで時間がかかるので、先頭行か末尾行の片方だけ処理したい場合は下記コマンドを利用してください。
(下記の方法では先頭行と末尾行の両方を抽出することはできません)
$ # 先頭行を抽出するコマンド
$ cat hoge.txt | sed '1q'
top
$
$ # 末尾行を抽出するコマンド
$ cat hoge.txt | tac | sed '1q'
end
$
また、-e
で複数コマンドを記載した際にそれぞれのコマンドでマッチすると、マッチした回数同じ行が出力されますので注意してください。
$ cat hoge.txt | sed -n -e '1p' -e '1p'
top
top
$
・行を抽出する(ファイル)
ファイルの先頭行や末尾行のみに書き換える方法です。
注意事項については上記の[行を抽出する(標準出力)]をご覧ください。
【コマンドの書き方】
sed -i -n '1p' (ファイルパス)
sed -i -n '$p' (ファイルパス)
sed -i -n -e '1p' -e '$p' (ファイルパス)
【コマンドのサンプル】
$ # 先頭行を抽出
$ sed -i -n '1p' hoge.txt
$
$ # 末尾行を抽出
$ sed -i -n '$p' hoge.txt
$
$ # 先頭行と末尾行を抽出
$ sed -i -n -e '1p' -e '$p' hoge.txt
$
sed
コマンドの他の操作方法
行の追加・削除・抽出と同様に標準出力の場合は(コマンド) |
、ファイルの場合はsed
コマンドに-i
オプションをつけてください。
・途中の行に追加する
【コマンドの書き方】
sed '(行数)i(追加する文字列)'
sed '(開始行数),(終了行数)i(追加する文字列)'
sed '/(文字列)/i(追加する文字列)'
sed '/(開始文字列)/,/(終了文字列)/i(追加する文字列)'
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle0
middle1
middle2
middle3
end
$
$ # 2行目に文字列ADDを追加
$ cat hoge.txt | sed '2iADD'
top
ADD
middle0
middle1
middle2
middle3
end
$
$ # 2行目と5行目に文字列ADDを追加
$ cat hoge.txt | sed -e '2iADD' -e '5iADD'
top
ADD
middle0
middle1
middle2
ADD
middle3
end
$
$ # 先頭行から2行目まで文字列ADDを追加
$ cat hoge.txt | sed '1,2iADD'
ADD
top
ADD
middle0
middle1
middle2
middle3
end
$
$ # 先頭行から2行目まで、5行目から末尾行までに文字列ADDを追加
$ cat hoge.txt | sed -e '1,2iADD' -e '5,$iADD'
ADD
top
ADD
middle0
middle1
middle2
ADD
middle3
ADD
end
$
$ # middle3が含まれる行に文字列ADDを追加
$ cat hoge.txt | sed '/middle3/iADD'
top
middle0
middle1
middle2
ADD
middle3
end
$
$ # middle2が含まれる行からmiddle3が含まれる行に文字列ADDを追加
$ cat hoge.txt | sed '/middle2/,/middle3/iADD'
top
middle0
middle1
ADD
middle2
ADD
middle3
end
$
・途中の行を削除する
【コマンドの書き方】
sed '(行数)d'
sed '(開始行数),(終了行数)d'
sed '/(文字列)/d'
sed '/(開始文字列)/,/(終了文字列)/d'
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle0
middle1
middle2
middle3
end
$
$ # 2行目を削除
$ cat hoge.txt | sed '2d'
top
middle1
middle2
middle3
end
$
$ # 2行目と5行目を削除
$ cat hoge.txt | sed -e '2d' -e '5d'
top
middle1
middle2
end
$
$ # 先頭行から2行目までを削除
$ cat hoge.txt | sed '1,2d'
middle1
middle2
middle3
end
$
$ # 先頭行から2行目まで、5行目から末尾行までを削除
$ cat hoge.txt | sed -e '1,2d' -e '5,$d'
middle1
middle2
$
$ # middle3が含まれる行を削除
$ cat hoge.txt | sed '/middle3/d'
top
middle0
middle1
middle2
end
$
$ # middle2が含まれる行からmiddle3が含まれる行を削除
$ cat hoge.txt | sed '/middle2/,/middle3/d'
top
middle0
middle1
end
$
・途中の行を抽出する
【コマンドの書き方】
sed -n '(行数)p'
sed -n '(開始行数),(終了行数)p'
sed -n '/(文字列)/p'
sed -n '/(開始文字列)/,/(終了文字列)/p'
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle0
middle1
middle2
middle3
end
$
$ # 2行目を抽出
$ cat hoge.txt | sed -n '2p'
middle0
$
$ # 2行目と5行目を抽出
$ cat hoge.txt | sed -n -e '2p' -e '5p'
middle0
middle3
$
$ # 先頭行から2行目までを抽出
$ cat hoge.txt | sed -n '1,2p'
top
middle0
$
$ # 先頭行から2行目まで、5行目から末尾行までを抽出
$ cat hoge.txt | sed -n -e '1,2p' -e '5,$p'
top
middle0
middle3
end
$
$ # middle3が含まれる行を抽出
$ cat hoge.txt | sed -n '/middle3/p'
middle3
$
$ # middle2が含まれる行からmiddle3が含まれる行に文字列ADDを抽出
$ cat hoge.txt | sed -n '/middle2/,/middle3/p'
middle2
middle3
$
・改行する
【コマンドの書き方】
sed '(行数)i(追加する文字列1)\n(追加する文字列2)'
sed '(行数)i(追加する文字列1)\
(追加する文字列2)'
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle
end
$
$ # 先頭行に文字列ADD1 改行(\n) ADD2を追加
$ cat hoge.txt | sed '1iADD1\nADD2'
ADD1
ADD2
top
middle
end
$
$ # 先頭行に文字列ADD1 改行(\) ADD2を追加
$ cat hoge.txt | sed '1iADD1\
> ADD2'
ADD1
ADD2
top
middle
end
$
・特殊文字を使う
【コマンドの書き方】
sed '(行数)i(追加する文字列) '\'' '
sed '(行数)i(追加する文字列) \\ '
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle
end
$
$ # 先頭行に記号を追加(大体そのまま使える)
$ cat hoge.txt | sed '1i!"#$%&()*+,-./:;<=>?@[]^_`{|}~'
!"#$%&()*+,-./:;<=>?@[]^_`{|}~
top
middle
end
$
$ # 先頭行に文字列ADD1と後続にシングルクォートを使用して追加`"
$ cat hoge.txt | sed '1iADD1'\''ADD2'
ADD1'ADD2
top
middle
end
$
$ # 先頭行に文字列ADD1と後続にバックスラッシュを使用して追加'
$ cat hoge.txt | sed '1iADD1\\ADD2'
ADD1\ADD2
top
middle
end
$
追加する文字列の先頭にあるスペースは省略されるので注意してください。
$ cat hoge.txt | sed '1i ADD'
ADD
top
middle
end
$
また、先頭にバックスラッシュを使用する場合は3つ連続(\\\
)記載する必要があるので注意してください。
$ cat hoge.txt | sed '1i\\\ADD'
\ADD
top
middle
end
$
・変数やコマンドを使う
【コマンドの書き方】
sed '(行数)i(追加する文字列) '変数' '
sed '(行数)eコマンド'
sed '(行数)i(追加する文字列) '$(コマンド)' '
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle
end
$
$ # 先頭行に文字列ADDと変数を追加
$ VAR=TEXT
$ cat hoge.txt | sed '1iADD '$VAR' '
ADD TEXT
top
middle
end
$
$ # 先頭行にdateコマンド結果を追加
$ cat hoge.txt | sed '1edate "+%Y/%m/%d %H:%M:%S"'
2022/07/10 01:12:12
top
middle
end
$
$ # 先頭行に文字列ADDとdateコマンド結果を追加
$ cat hoge.txt | sed '1iADD '$(date "+%Y/%m/%d_%H:%M:%S")' '
ADD 2022/07/10_01:42:59
top
middle
end
$
$(コマンド)
でスペースの入ったコマンド結果を追加する場合は"$(コマンド)"
のようにダブルクォートで結果を囲う必要があります。
$ cat hoge.txt | sed '1iADD '$(date "+%Y/%m/%d %H:%M:%S")' '
sed: 01:49:54 を読み込めません: そのようなファイルやディレクトリはありません
$
$ cat hoge.txt | sed '1iADD '"$(date "+%Y/%m/%d %H:%M:%S")"' '
ADD 2022/07/10 01:50:08
top
middle
end
$
sed
コマンド以外を使用する方法
・行を追加する
sed
コマンドを学んでいくと忘れがちになりますが、ファイルの末尾行に文字列を追加するにはコマンド結果の追記のリダイレクト(>>
)が使用できます。
sed
コマンドより処理速度が早くメモリ使用量が少ないので、特に理由がなければこちらを使用することをオススメします。
【コマンドの書き方】
cat (末尾行に追加したい文字列のファイルパス) >> (ファイルパス)
echo "末尾行に追加したい文字列" >> (ファイルパス)
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle
end
$
$ # fuga.txtの中身
$ cat fuga.txt
fuga top
fuga middle
fuga end
$
$ # 末尾行にfuga.txtの文字列を追加
$ cat fuga.txt >> hoge.txt
$
$ # 末尾行に文字列ADDを追加
$ echo "ADD" >> hoge.txt
$
また、標準出力の先頭行や末尾行に文字列を追加する方法としてもcat
コマンドを使用することができます。
下記は先頭行に文字列を追加する方法になります。
【コマンドの書き方】
cat (先頭行に追加したい文字列のファイルパス) -
cat <(echo "先頭行に追加したい文字列") -
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle
end
$
$ # fuga.txtの中身
$ cat fuga.txt
fuga top
fuga middle
fuga end
$
$ # 先頭行にfuga.txtの文字列を追加
$ cat hoge.txt | cat fuga.txt -
fuga top
fuga middle
fuga end
top
middle
end
$
$ # 先頭行に文字列ADDを追加
$ cat hoge.txt | cat <(echo "ADD") -
ADD
top
middle
end
$
下記は末尾行に文字列を追加する方法になります。
【コマンドの書き方】
cat - (末尾行に追加したい文字列のファイルパス)
cat - <(echo "末尾行に追加したい文字列")
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle
end
$
$ # fuga.txtの中身
$ cat fuga.txt
fuga top
fuga middle
fuga end
$
$ # 先頭行にfuga.txtの文字列を追加
$ cat hoge.txt | cat - fuga.txt
top
middle
end
fuga top
fuga middle
fuga end
$
$ # 先頭行に文字列ADDを追加
$ cat hoge.txt | cat - <(echo "ADD")
top
middle
end
ADD
$
下記は先頭行と末尾行に文字列を追加する方法になります。
【コマンドの書き方】
cat (先頭行に追加したい文字列のファイルパス) - (末尾行に追加したい文字列のファイルパス)
cat <(echo "先頭行に追加したい文字列") - <(echo "末尾行に追加したい文字列")
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle
end
$
$ # fuga.txtの中身
$ cat fuga.txt
fuga top
fuga middle
fuga end
$
$ # 先頭行と末尾行にfuga.txtの文字列を追加
$ cat hoge.txt | cat fuga.txt - fuga.txt
fuga top
fuga middle
fuga end
top
middle
end
fuga top
fuga middle
fuga end
$
$ # 先頭行と末尾行に文字列ADDを追加
$ cat hoge.txt | cat <(echo "ADD") - <(echo "ADD")
ADD
top
middle
end
ADD
$
・行を削除する
grep
コマンドでも特定の文字列が含まれる行を削除することができます。
【コマンドの書き方】
(コマンド) | grep -v (文字列)
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle
end
$
$ # middleが含まれる行を削除
$ cat hoge.txt | grep -v middle
top
end
$
また、awk
コマンドでも指定した行を削除することができます。
【コマンドの書き方】
(コマンド) | awk 'NR!=(行数)'
(コマンド) | awk '!/(文字列)/'
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle
end
$
$ # 2行目を削除
$ cat hoge.txt | awk 'NR!=2'
top
end
$
$ # middleが含まれる行を削除
$ cat hoge.txt | awk 'NR!/middle/'
top
middle
end
$
・行を抽出する
head
コマンド、tail
コマンド、grep
コマンドを使用して行を抽出することができます。
この3つのコマンドはsed
コマンドより処理速度が早くメモリ使用量も少ないので、大量のデータを処理する際はこちらを使用することをオススメします。
【コマンドの書き方】
(コマンド) | head -(行数)
(コマンド) | tail -(行数)
(コマンド) | grep 文字列
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle0
middle1
middle2
middle3
end
$
$ # 先頭行から2行目までを抽出
$ cat hoge.txt | head -2
top
middle0
$
$ # 末尾行から2行目までを抽出
$ cat hoge.txt | tail -2
middle3
end
$
$ # middleが含まれる行を抽出
$ cat hoge.txt | grep middle
middle0
middle1
middle2
middle3
$
また、複数のコマンドを同時に実行することができます。
【コマンドの書き方】
(head -(行数);tail -(行数)) <(ファイルパス)
(head -(行数);grep 文字列) <(ファイルパス)
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle0
middle1
middle2
middle3
end
$
$ # 先頭行と末尾業を抽出
$ (head -1;tail -1) < hoge.txt
top
end
$
$ # 先頭行とmiddleが含まれる行を抽出
$ (head -1;grep middle) < hoge.txt
top
middle0
middle1
middle2
middle3
$
また、awkコマンドでも指定した行や特定の文字列が含まれる行を抽出することができます。
【コマンドの書き方】
(コマンド) | awk 'NR==(行数)'
(コマンド) | awk '/(文字列)/'
【コマンドのサンプル】
$ # hoge.txtの中身
$ cat hoge.txt
top
middle0
middle1
middle2
middle3
end
$
$ # 2行目を抽出
$ cat hoge.txt | awk 'NR==2'
middle0
$
$ # 先頭行から2行目までを抽出
$ cat hoge.txt | awk 'NR<=2'
top
middle0
$
$ # middleが含まれる行を抽出
$ cat hoge.txt | awk '/middle/'
middle0
middle1
middle2
middle3
$
$ # 先頭行とmiddleが含まれる行を抽出
$ cat hoge.txt | awk 'NR==1||/middle/'
top
middle0
middle1
middle2
middle3
$
・長く複雑な文字列を追加する
sed
コマンド以外に標準出力のテキストを操作する方法としてcat
コマンドが使用できます。
こちらの方法ではバックスラッシュなどを行末につけなくても複数行追加でき、shellの変数やコマンドも使用できます。
また、ダブルクォート("")やシングルクォート('')は対になっていればエスケープせずに使用できます。
【コマンドの書き方】
(コマンド) | cat <(cat <<EOF
先頭行に追加したい文字列
EOF
) -
(コマンド) | cat - <(cat <<EOF
末尾行に追加したい文字列
EOF
)
(コマンド) | cat <(cat <<EOF
先頭行に追加したい文字列
EOF
) - <(cat <<EOF
末尾行に追加したい文字列
EOF
)
【コマンドのサンプル】
$ cat hoge.txt
top
middle
end
$
$ cat hoge.txt | cat <(cat <<EOF
> header1 変数:$PWD、コマンド:$(date "+%Y/%m/%d-%H:%M:%S")
> header2 'シングル' + "ダブル"
> EOF
> ) -
header1 変数:/home/hoge、コマンド:2022/07/10-11:26:35
header2 'シングル' + "ダブル"
top
middle
end
$
$ cat hoge.txt | cat - <(cat <<EOF
> footer1 変数:$PWD、コマンド:$(date "+%Y/%m/%d-%H:%M:%S")
> footer2 'シングル' + "ダブル"
> EOF
> ) -
top
middle
end
footer1 変数:/home/hoge、コマンド:2022/07/10-11:27:35
footer2 'シングル' + "ダブル"
$ cat hoge.txt | cat <(cat <<EOF
> header1 変数:$PWD、コマンド:$(date "+%Y/%m/%d-%H:%M:%S")
> header2 'シングル' + "ダブル"
> EOF
> ) - <(cat <<EOF
> footer1 変数:$PWD、コマンド:$(date "+%Y/%m/%d-%H:%M:%S")
> footer2 'シングル' + "ダブル"
> EOF
> )
header1 変数:/home/hoge、コマンド:2022/07/10-11:29:06
header2 'シングル' + "ダブル"
top
middle
end
footer1 変数:/home/hoge、コマンド:2022/07/10-11:29:06
footer2 'シングル' + "ダブル"
変数やコマンドを展開せずに表示したい場合はEOFをシングルクォートで囲ってください。
$ cat hoge.txt | cat <(cat <<'EOF'
> header1 変数:$PWD、コマンド:$(date "+%Y/%m/%d-%H:%M:%S")
> header2 'シングル' + "ダブル"
> EOF
> ) -
header1 変数:$PWD、コマンド:$(date "+%Y/%m/%d-%H:%M:%S")
header2 'シングル' + "ダブル"
top
middle
end
コマンドの使い分け
・数やサイズによってコマンドを変える
sed
コマンドでは柔軟な操作ができますが、大量のデータやサイズの大きなファイルを扱う場合は処理に時間がかかり、メモリの消費も大きくなります。
そういう場合に先頭行や末尾行の抽出を行う際にはsed
コマンドではなく、head
コマンドやtail
コマンドを使用すると早く処理でき、メモリの消費量も少なくなります。
$ # sedコマンドで先頭行と末尾行を抽出
$ sed -n -e '1p' -e '$p' hoge.txt
top
end
$
$ # headコマンドとtailコマンドで先頭行と末尾行を抽出
$ (head -1;tail -1) <hoge.txt
top
end
$
ちなみに手元にあった1G(800万行)のファイルで上記のコマンドを10回実行した際の時間を計測してみたところ、sed
コマンドはhead
コマンド + tail
コマンドの組み合わせの400倍の時間がかかりました。
sed
コマンドで大量のデータやサイズの大きなファイルを扱う場合は[行を抽出する(標準出力)]の注意事項に記載しているq
コマンドを使用してください。
また、文字列を含む行の抽出についても大量のデータやサイズの大きなファイルの場合はsed
コマンドではなくgrep
コマンドを使用すると早く処理でき、メモリの消費量も少なくなります。
参考までにgrep
コマンドを基準として、上記で計測したファイルから文字列が含まれる行を抽出する際にかかった時間をコマンド別に倍率で記載しておきます。
コマンド | 倍率 |
---|---|
grep | 1.0 |
sed | 4.4 |
perl | 4.5 |
awk | 5.5 |
先頭行と末尾行を抽出した計測ほど圧倒的な差はありませんが、grep
コマンドの強力な性能はイメージできたと思います。
・後続処理によってコマンドを変える
数やサイズの小さなデータで単純に行の追加・削除・抽出だけを行いたいのであればsed
コマンドで十分ですが、その後に処理が継続するようであれば、後続処理の内容によってコマンドを変更する方がシンプルに記述できる場合があります。
例えば特定文字列がある行を抽出し、行の1番目の項目を抜き出したい...といった場合は、sed
コマンドで行の抽出をしてからawk
コマンドで項目の抜きだすより、初めからawk
コマンドを使用して行の抽出と項目の抜きだす方がシンプルに記述できます。
$ # fuga.txtの中身
$ cat fuga.txt
fuga top
fuga middle
fuga end
$
$ # sedでmiddleが含まれる文字を抽出し、awkで1項目目を抜き出し
$ cat fuga.txt | sed -n '/middle/p' | awk '{print $1}'
fuga
$
$ # awkだけでmiddleが含まれる文字を抽出し、1項目目を抜き出し
$ cat fuga.txt | awk '/middle/{print $1}'
fuga
$
また、1行目にあるヘッダーと文字列が含まれる行を抽出したい場合はsed
コマンドでも実現できますが、grep
コマンド、awk
コマンドでも代替できる場合があります。
単純に抽出処理だけしたい場合はgrep
コマンド、後続処理が文字列置換であればsed
コマンド、後続処理が項目の抜き出しや集計であればawk
コマンドを使用するなど、後続処理によってコマンドを変える方がシンプルに記述できます。
$ # sedコマンドを使用してpsコマンドの結果をヘッダーを残しつつnginxが含まれる行を抽出
$ ps aux | sed -n -e '1p' -e '/[n]ginx/p'
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 287 0.0 0.0 1176 100 ? Ss Jul10 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx 287 0.0 0.0 1189 119 ? S Jul10 0:27 nginx: worker process
nginx 287 0.0 0.0 1190 122 ? S Jul10 0:26 nginx: worker process
$
$ # grepコマンドを使用してpsコマンドの結果をヘッダーを残しつつnginxが含まれる行を抽出
$ ps aux | grep -e ^USER -e [n]ginx
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 287 0.0 0.0 1176 100 ? Ss Jul10 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx 287 0.0 0.0 1189 119 ? S Jul10 0:27 nginx: worker process
nginx 287 0.0 0.0 1190 122 ? S Jul10 0:26 nginx: worker process
$
$ # awkコマンドを使用してpsコマンドの結果をヘッダーを残しつつnginxが含まれる行を抽出
$ ps aux | awk 'NR==1||/[n]ginx/'
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 287 0.0 0.0 1176 100 ? Ss Jul10 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx 287 0.0 0.0 1189 119 ? S Jul10 0:27 nginx: worker process
nginx 287 0.0 0.0 1190 122 ? S Jul10 0:26 nginx: worker process
$
上記のサンプルでは抽出コマンドのプロセスの表示を除外するために抽出対象の文字列の
先頭文字を[]
で囲っています。
抽出コマンドのプロセスを除外する必要がなければ[]
で囲う必要はありません。
$ ps aux | sed -n -e '1p' -e '/nginx/p'
USER PID %CPU %MEM STAT START TIME COMMAND
root 287 0.0 0.0 Ss Jul10 0:00 nginx: master
nginx 287 0.0 0.0 S Jul10 0:27 nginx: worker
nginx 287 0.0 0.0 S Jul10 0:26 nginx: worker
piyo 106 0.0 0.0 S+ 13:48 0:00 sed -n -e 1p -e /nginx/p
$
・文字列によってコマンドを変える
1行(ワンライナー)で全てのコマンドを記述する必要がない限り、固定された長い文字列を追加する場合は、文字列をファイルに格納してcat
コマンドを使用する方法をオススメします。
改行、特殊文字、変数やコマンドなども気にする必要がなく、コマンド自体の可読性も上がるので、無理にsed
コマンドで頑張る必要はありません。
(使い方は[sed
コマンド以外を使用する方法 - 行を追加する]のcat
コマンドを参照)
また、ワンライナーの場合でも、SQLなどのシングルクォートが頻繁に出てくる文字列を扱う場合はエスケープするのが面倒だったり、変数やコマンドを使用したかったりするケースは多いと思いますが、そんな場合はcat
コマンドとプロセス置換(<()
)、ヒアドキュメント(<<
)を使用すると比較的自由に文字列を追加することができます。
(使い方は[sed
コマンド以外を使用する方法 - 長く複雑な文字列を追加する]参照)
sed
コマンド操作の解説
今回紹介したsed
コマンドの操作について、簡単に解説を記載していきます。
下記はよく見るsed
コマンドの使い方で、ファイルの中身を読み取って全ての行に対して置換処理を行い結果を標準出力へ出力しています。(^
は行の先頭を意味します)
top
middle
end
$ sed -e 's/^/ADD /' hoge.txt
ADD top
ADD middle
ADD end
$
また、sed
コマンドではスクリプトコマンドの前にアドレス(処理を行う対象の行数)を指定でき、省略した場合は全行が処理の対象となります。
$ # 2行目の先頭をADDに置換
$ sed -e '2s/^/ADD /' hoge.txt
top
ADD middle
end
$
上記のコマンドを分解すると下記のようになります。
本稿で使用しているオプション、アドレス、スクリプトコマンド、入力、出力の意味は下記の通りになります。
- オプションの説明
オプション | 説明 |
---|---|
-e |
スクリプトコマンドを実行する。 (一つだけの場合は省略可能で、複数指定可能) |
-i |
入力ファイルとして指定したファイルを書き換える。 |
-n |
読み込んだテキストを出力しない。 (指定しない場合は読み込んだテキストを全て出力) |
- アドレスの説明
アドレス | 説明 |
---|---|
数字 |
数字 の行を指定する。 |
$ |
末尾行を指定する。 |
/文字列/ |
文字列 が含まれる行を指定する。 |
開始行,終了行 |
開始行 から終了行 までを指定する。 |
/開始文字列/,/終了文字列/ |
開始文字列 が含まれる行から終了文字列 が含まれる行を指定する。 |
- スクリプトコマンドの説明
スクリプトコマンド | 説明 |
---|---|
s/置換前/置換後/ |
指定した行の置換前 の文字列を置換後 の文字列に置き換える。 |
i文字列 |
指定した行の前に文字列 + 改行 を追加する。 |
a文字列 |
指定した行の後に文字列 + 改行 を追加する。 |
p |
指定した行を出力する。 |
d |
指定した行を削除する。 |
q |
指定した行を出力してコマンドを終了する。 |
Q |
指定した行でコマンドを終了する。(出力しない) |
eコマンド |
コマンド の実行結果を指定した行の前に追加する。 |
-
sed
コマンドへの入力の説明
sed
コマンドで処理させたいテキストを渡す方法は上記のようにsed
コマンドの引数として入力ファイルのパスを指定する方法と、sed
コマンドの標準入力にテキストを渡す方法の2種類あります。
$ # sedコマンドの引数としてhoge.txtを渡す
$ sed -e 's/^/ADD /' hoge.txt
ADD top
ADD middle
ADD end
$
$ # プロセス置換を使用してsedコマンドの引数としてhoge.txtを渡す
$ sed -e 's/^/ADD /' <(cat hoge.txt)
ADD top
ADD middle
ADD end
$
$ # catコマンドの標準出力をパイプを使用してsedコマンドの標準入力に渡す
$ cat hoge.txt | sed -e 's/^/ADD /' hoge.txt
ADD top
ADD middle
ADD end
$
$ # 標準入力へのリダイレクトを使用してsedコマンドの標準入力にhoge.txtの中身を渡す
$ sed -e 's/^/ADD /' <hoge.txt
ADD top
ADD middle
ADD end
$
-
sed
コマンドの出力の説明
sed
コマンドで処理した結果を出力する方法として標準出力に出力する、sed
コマンドの-i
オプションを使用して入力ファイルに出力する(書き換える)、別なファイルに出力する、の3種類があります。
$ sed -e 's/^/ADD /' hoge.txt
ADD top
ADD middle
ADD end
$
$ sed -i -e 's/^/ADD /' hoge.txt
$ cat hoge.txt
ADD top
ADD middle
ADD end
$
$ sed -e 's/^/ADD /' hoge.txt > piyo.txt
$ cat piyo.txt
ADD top
ADD middle
ADD end
$
sed
コマンドは入力されたテキストの先頭行から末尾行まで読み込んで処理していきます。
そのため、先頭行のみ抽出するような下記コマンドであっても末尾行まで読みに行くため、読み込むテキストが大きい場合は処理に時間がかかるので注意してください。
$ sed -n '1p' hoge.txt
top
$
なお、q
コマンドやQ
コマンドを使用すると、末尾行まで読み込まずに指定した行で読み込みを中止してくれます。
本稿で紹介した使用方法は解説した内容の応用で実現していますが、sed
コマンドそのものを理解するともっと柔軟に応用できますので興味のある方は是非sed
コマンドのmanや解説サイトをご覧ください。
おわりに
だいぶ文章や普段使用しなさそうな記述を削ったつもりですが、分量が多すぎて見にくいかもしれません。
本来はそれぞれの解説を書く予定でしたが、それは別の記事として投稿しようと思います。
コマンドのサンプルだけだと応用ができなくなってしまうので、できるだけ文章を削ってsed
コマンドの簡単な解説を追加しました。
また、[Linux初心者がコマンドを使うときに知っておくと少し幸せになること]でも基本的なコマンドの使い方を紹介しているので、本稿の記載で分からない部分があればそちらを確認すると解決するかもしれません。