sedやawkを使ったファイルや文字の操作

1.リダイレクト

まずは、リダイレクトのファイル操作
❶リダイレクト >  新規作成
ファイルに文字列を出力する。既存のファイルがある場合は完全なる上書き。つまり、前のデータは消える。

echo '123' > file1.txt

❷リダイレクト >>  追記
以下の場合は、ファイルに追記する。ファイルが無い場合には、>と同じ動きになる。

echo '456' >> file1.txt

2.sed

1.sedについて

まずは、バージョンの確認

sed --version

・-i でファイルを上書き保存。
・-e や -i オプション、オプションを付けない場合がある。-eや何もつけない場合は、画面出力だけで、実際に変更はしていない。だから、リダイレクトでファイルに出力する方法もできる。
例①
file1.txtにあるlinuxをwindowsに置換して、そのファイルをfile2.txtにする

sed -e 's/linux/windows/g' file1.txt > file2.txt

例②
上記で、linuxの文字を消すには

sed -e 's/linux//g' file1.txt > file2.txt

2.文字の置換

(1)文字の置換

・基本構文は s/変換前の文字列/変換後の文字列/ である。
・sの代わりにyを使うと、文字列ではなく、1文字ずつ処理される。たとえば、y/abc/ABC とすると、a→A、b→B、c→Cに変換する。s/abc/ABC であれば、abc→ABCに変換
・最後の/のあとに何もつけないと、最初の1つだけ置換する。これはこれで便利。/gとすると、全て置換する。
・囲い方は、ダブルクォーテション"でもいいが、シングル'の方がいいだろう。'を使えば、/、"、<をエスケープしなくてもいい。
・1つのファイルに複数の置換をする場合は、 -e でつなげる。
・最終行は$ 、行頭は^ 、任意の文字列は.* 、改行 \n 、タブは\t。

❶文字の置換・・・最初に見つけたの文字列だけ

sed -i 's/=enforcing/=disabled/' /etc/selinux/config

❷文字の置換 ・・・ 全ての文字

sed -i 's/a/A/g' file1.txt

❸書き方の注意点
操作するファイルの位置というか、構文
・正しい書き方は、以下

sed -i 's/a/A/g' a.txt

・以下はエラーになる。

sed -i a.txt 's/a/A/g'

・ファイル名を先頭に持ってくる(その方が分かりやすい場合があり)場合は、-eをつければOK。

sed -i a.txt -e 's/a/A/g'

❹特定の行の文字だけを置換
たとえば、先頭が12で始まる(⇒^12)で始まる行のwをWに置換する。

sed -i '/^12/ s/w/W/' file1.txt

※もちろん、すべて置換する場合はs/w/W/gとする。
これを活用すると、たとえば、#inet_interfaces = all という行の#のコメントアウトを外すことができる。

sed -i '/#inet_interfaces = all/ s/^#//' /etc/postfix/main.cf 
(2)複雑な文字の置換

・正規表現でいろいろできるので、やってみたい。
❶数字の1~5を見つけたら、それに-を付与する。
[1-5]は、1~5のどれかという意味。&は、正規表現による文字そのもの。今回は-としているが、これは単なる文字列。&-に置換している。よって、「1」は「1-」に置換、「2」は「2-」に置換。

sed -i 's/[1-5]/&-/g' a.txt

❷ループで回すなど、変数を使う場合
これは少し注意が必要で、iという変数をsedで使う場合、${i}と'$i'の両方を使っている。こうしないとできない。
以下の場合は、gp1_userは5000を5001にし、gp2_userは5000を5002に置換している。
#!/bin/bash
for i in {1..3};do
sed -i /home/gp${i}_user/sql-injection.py -e 's/5000/500'$i'/'
done
|

(3)行の追加

・構文は以下。行番号の後ろに i を付けると、その行の前に追加。aを付けると、後ろに追加
sed -i '行番号i 文字列' file1.txt
・多くの場合は、先頭か末尾に加えると思う。

❶先頭、または、指定された行に行というか文字列を足す。
1iの1は、1行目、iはinsert、\は区切り文字とでも考えればいいだろう。★次に書いたように、\の代わりにスペースがいいかも。
以下は、introductionという文字が1行追加される。追加するファイルはfile1.txt

sed -i '1i\introduction' file1.txt

・\ではなく、スペースでもいい。また、文字列にスペースが入ったとしても、そのまま入力できる。以下は「into duct」という空白ありの文字を挿入する場合

sed -i '1i intro duct' file1.txt

・やってることは既に説明したことであるが、例として。105iとすることで、105行目に追加

sed -i /etc/httpd/conf/httpd.conf -e '105i Options Indexes FollowSymLinks' 

❷末尾に行を足す その1 echo
・末尾の場合は、リダイレクト>>の方が分かりやすいかもしれない。

echo 'introduction' >> file1.txt

・改行コード\nを入れる場合などには、-eを付ける。以下は、改行してendという文字を追加する。(合計2行)。このやり方だと、何行でも追加できる。スペースや特殊文字/などが入っていても問題はない。

echo -e '\nend'>>file1.txt

❸末尾に行を足す その2 sed
$は末尾を指し、aはattendかaddだと思う。\は区切り文字とでも考えればいいだろう。

sed -i '$a\introduction' file1.txt

※$とaの間はスペースでもいい。また、すでに説明したが、\の代わりに空白でもいい。以下のようになる。

sed -i '$ a introduction' file1.txt

❹特定の文字列をキーに行を挿入 その1
・これは、Wordという文字がある行の上に、abcdeという文字を1行挿入する。
注意点は、1つだけでなく、全ての文字で置換を実行する。

sed -i '/Word/i abcde' file1.txt

・該当文字の後ろに追加する場合は、iの代わりにaを使う

sed -i '/Word/a abcde' file1.txt

❺特定の文字列をキーに行を挿入 その2
今度は、文の先頭や文末に決められた文字がある場合。
たとえば、先頭にWordという文字を指定するには、行頭(その行の先頭)を意味する^を付けて、^Word とする。行末(その行の最後)は$。行頭と行末の両方を指定してもいい。

sed -i '/^Word/i abcde' file1.txt

・以下は、行の先頭と、行末の言葉を指定し、間はアスタリスク(*)で指定。つまり、行の先頭が「Wor」で始まり、「d」で終わる行に追加。今回はaを指定しているので、行の後ろに追加。

sed -i '/^Wor.*d$/a abcde' file1.txt
(4)行の削除

❶5行目を削除
・5行目を削除するのは以下のように5dと指定する。5行目をdeleteという意味。
・また、-iを付ける。

sed -i '5d' file1.txt

・-eや、何もオプションを付けない場合。
→本当に削除はせず、削除した結果を画面出力しているだけ。

sed -e '5d' file1.txt

❷複数指定する場合
: で続ける

sed -i '1d:3d:5d' file1.txt

❸範囲を指定する場合
 , を使う。

sed -i '1d,5d' file1.txt

❹正規表現
・空白行を削除する。正規表現を使って以下のようになる。

sed -i '/^$/d' file1.txt
(5)実際の例

❶sshdの設定ファイルで設定を有効に
元ファイルは以下であり、yesを有効にし、noに#をつける

#PasswordAuthentication yes
PasswordAuthentication no

流し込むスクリプトとしては、以下

sed -i '/^#PasswordAuthentication yes/ s/#//' /etc/ssh/sshd_config
sed -i '/^PasswordAuthentication no/ s/PasswordAuthentication no/#PasswordAuthentication no/' /etc/ssh/sshd_config

❷CGIを有効にする
元ファイルは以下であり、行頭に空白が空いている。

   Options Indexes FollowSymLinks
   #AddHandler cgi-script .cgi

これを、以下に変更する。2つ目は#を取るだけ。

   Options Indexes ExecCGI FollowSymLinks
   AddHandler cgi-script .cgi

流し込むスクリプトとしては、以下。先頭にない場合は^が不要で、いきなり置換すればいい。また、gをつけなければ1回だけの置換になる。

sed -i 's/Options Indexes FollowSymLinks/Options Indexes ExecCGI FollowSymLinks/' /etc/httpd/conf/httpd.conf
sed -i '/#AddHandler cgi-script .cgi/ s/#//' /etc/httpd/conf/httpd.conf

❸ポート番号を変える
/etc/sysconfig/shellinaboxdの元ファイルは以下。

PORT=4200

これを、以下に変更する。2つ目は#を取るだけ。

#PORT=4200
PORT=8000

流し込むスクリプトとしては、以下。2行を改行コード\nでつなげている。

sed -i '/^PORT=4200/ s/PORT=4200/#PORT=4200\nPORT=8000/' /etc/sysconfig/shellinaboxd

3.awk(オーク)とcut

1.awk

ログのように、カンマ(やスペース)で区切られたファイルの3番目の項目だけを表示したいなどの要件があると思う。それがこれ。
スペースで区切られている場合はデフォルトでいけるが、区切り文字がスペース以外の場合は、-F "," などと指定する。
①ls -la でファイル名のみ表示
#ls -la | awk '{print $9}'
②ログの1列目と7列目のみを表示
#cat access.log | awk '{print $1,$7}'
③上記において、ファイルの区切り文字が , の場合
#cat access.log | awk -F "," '{print $1,$7}'

(2)重複排除(uniq)とカウント(-c)
・uniqで重複を排除、-cオプションで件数を数える
・sortで並び替え -rで降順、-nで文字の場合も数字として扱う
④送信元IP(1列目)で重複を消してカウント uniq -c ※なぜか先にsortするとうまくいく。
#cat access.log | awk -F "," '{print $1}' | sort | uniq -c
※sort しないと、件数が増える。違う列もカウントして、その後、Uniqをしているのだろうか。もう少し調べる必要がありそう。
⑤その結果を、カウント順に並べるには、さらに sortを付ける

2.cut

cut -c 文字を切り取り

❶以下は/etc/passwdからvulnuserのIDを取得する。

#/etc/passwdからvulnuserの情報を見ておこう
cat /etc/passwd | grep vulnuser  # ==>  vulnuser:x:1014:1014::/home/vulnuser:/bin/bash
#変数aに、この結果を入れる
a=(`cat /etc/passwd | grep vulnuser`)
#区切り文字を:に指定して、切り取り、3つ目を変数bに入れる
b=`echo ${a} | cut -d ':' -f 3`
echo $b  # ==> 1014

https://xtech.nikkei.com/it/article/COLUMN/20060228/231159/
curl --url http://172.31.36.241/index.html -X GET | grep abc | cut -c 3-5 >>log.txt