sedでは1行目からn行目までの範囲に対して処理をするように指定できるのだが、最終行からn行に対してのみ置換などの処理を行わせたい場合、普通には指定ができない。 たとえば、以下のようにしてすることで頭の4行のみを対象とする事はできるのだが、後ろの4行を対象に処理をさせることはできない。

sed '1,4s/^/#/g' test # 先頭4行のみを対象とする。これは動く
sed '$-4,$s/^/#/g' test # 末尾4行を対象にしたいが、マイナスは指定できないのでこれは動かない
[root@BS-PUB-CENT7-01 ~]# cat test
1
2
3
4
5
6
7
8
9
10
[root@BS-PUB-CENT7-01 ~]# sed '1,4s/^/#/g' test # 先頭4行のみを対象とする。これは動く
#1
#2
#3
#4
5
6
7
8
9
10
[root@BS-PUB-CENT7-01 ~]# sed '$-4,$s/^/#/g' test # 末尾4行を対象にしたいが、マイナスは指定できないのでこれは動かない
sed: -e expression #1, char 2: 不明なコマンド: `-'

じゃ、末尾の数行に対してのみ処理を行わせる場合、どうすればよいのか。

1. sedの場合

sedでの例。 2つほど例を出してみる(Nのトコに数字が入る)。

よくある方法としては、tacと組み合わせて処理をする方法だろうか。 wcと組み合わせる方法であれば上書きなどもできるので、状況に応じて使い分けるといいだろう。

tac file | sed '1,Ns/^/#/g' | tac
sed "$(($(wc -l < test)-N+1)),\$s/^/#/g" file
[root@BS-PUB-CENT7-01 ~]# tac test | sed '1,3s/^/#/g' | tac
1
2
3
4
5
6
7
#8
#9
#10
[root@BS-PUB-CENT7-01 ~]# sed "$(($(wc -l < test)-3+1)),\$s/^/#/g" test
1
2
3
4
5
6
7
#8
#9
#10

2. awkの場合

一応、awkでも同じような処理ができる。 まぁ、awkが使える環境ならsedも使えるだろうし、あまり使うことはないだろう。

awk '{buf[NR-1]=$0;}END{x=N;for(i=0;i<NR;i++){if(i>(NR-x-1)){gsub("^","#",buf[i])};print buf[i];}}' file
[root@BS-PUB-CENT7-01 ~]# awk '{buf[NR-1]=$0;}END{x=3;for(i=0;i<NR;i++){if(i>(NR-x-1)){gsub("^","#",buf[i])};print buf[i];}}' test
1
2
3
4
5
6
7
#8
#9
#10