
ファイルを一行ずつ読み込んでいます。各行は次のようになります。
xxyu: JHYU_IOPI
各行は以下のようにawkに渡されます。パターンに一致する前の行を印刷したいです。 grepを使ってこれを行うことができ、awkでどこでミスをするのか知りたいです。
#!/bin/bash
while read i
do
awk '/$i/{print a}{a=$0}' ver_in.txt
done<in.txt
私もこれを試しました:
#!/bin/bash
while read i
do
awk -v var="$i" '/var/{print a}{a=$0}' jil.txt
done<in.txt
編集:sh readを使用しないようにアドバイスを受けた後、awkを使用しました。私の入力と希望の出力は次のとおりです。
編集1:@ Ed Mortonのawkスクリプトへの入力を次のように編集しました。
入力ファイル:catファイル
/* ----------------- AIX_RUN_WATCH ----------------- */
insert_job: AIX_RUN_WATCH job_type: BOX
owner: root
permission:
date_conditions: 1
days_of_week: su
start_times: "22:00"
alarm_if_fail: 1
alarm_if_terminated: 1
group: app
send_notification: 0
notification_emailaddress:
/* ----------------- AIX_stop ----------------- */
insert_job: AIXstop job_type: CMD
box_name: AIX_RUN_WATCH
command: ls
machine: cfg.mc
owner: root
permission:
date_conditions: 0
box_terminator: 1
std_out_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stdout"
std_err_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stderr"
alarm_if_fail: 1
alarm_if_terminated: 1
group: app
send_notification: 1
/* ----------------- AIX_start ----------------- */
insert_job: AIX_start job_type: CMD
box_name: AIX_RUN_WATCH
command: ls
machine: cfg.mc
owner: root
permission:
date_conditions: 0
box_terminator: 1
std_out_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stdout"
std_err_file: ">> /tmp/${AUTOSERV}.${AUTO_JOB_NAME}.$(date +%Y%m%d).stderr"
alarm_if_fail: 1
alarm_if_terminated: 1
group: app
cat targets
box_name: AIX_RUN_WATCH
予想出力 -
box_name: AIX_RUN_WATCH
insert_job: AIX_stop
insert_job: AIX_start
答え1
最初の試みでは、シェル変数拡張に二重引用符を使用してから、$
awk演算子をエスケープしてシェル拡張を防ぐ必要があります。ただし、変数にawk$i
などの特殊文字(たとえば、、)が含まれていることに注意してください。 [今は、コマンドに関連する1つ以上の他の問題を解決することをスキップします]。\
/
while read i
do
awk "/$i/{print a}{a=\$0}" ver_in.txt
done<in.txt
2番目の試みでは、現在の行で正規表現一致または文字列一致を使用する必要があります。たとえば、正規表現一致(部分正規表現一致)を使用します。
while read i
do
awk -v var="$i" '$0 ~ var{print a}{a=$0}' jil.txt
done<in.txt
または、次の文字列一致(完全な文字列一致)です。
while read i
do
awk -v var="$i" '$0==var{print a}{a=$0}' jil.txt
done<in.txt
パターンに一致する前の行を印刷するために使用したいコマンドについて話したら、awkを使用してすべての操作を実行してから、完全な文字列一致を実行するシェルループの使用を停止できます。
awk 'NR==FNR { str[$0]; next }
($0 in str) && prev!="" { print prev } { prev=$0 }' in.txt ver_in.txt
または部分正規表現マッチングを実行します。
awk 'NR==FNR { patt[$0]; next }
{ for(ptrn in patt) if($0 ~ ptrn && prev!="") print prev; prev=$0 }' in.txt ver_in.txt
または部分文字列マッチングを実行します。
awk 'NR==FNR { strings[$0]; next }
{ for(str in strings) if(index($0, str) && prev!="") print prev; prev=$0 }' in.txt ver_in.txt
または、完全正規表現マッチングを実行します。
awk 'NR==FNR { patt[$0]; next }
{ for(ptrn in patt) if($0 ~ "^"ptrn"$" && prev!="") print prev; prev=$0 }' in.txt ver_in.txt
答え2
このために読み込み中にループは必要なく、shでテキストを処理するのは悪い考えです(参照シェルループを使用してテキストを処理するのはなぜ悪い習慣と見なされますか?)。
代わりに、awkスクリプトに両方のファイルを処理させるようにしてください。
awk 'NR==FNR { re = $0 "|" re ; next}; # append input line and | to re
FNR == 1 { sub(/\|$/,"",re) }; # remove trailing | on 1st line of 2nd file
$0 ~ re { print a }; # if the current line matches re, print a
{a = $0}' in.txt ver_in.txt
最初のファイル()を読み取るときに、各入力行と「交互」の正規表現を追加して、呼び出される変数に正規in.txt
表現を作成します(例:re
または)オペレータ。
最初のファイルの読み取りが終わったら、最初にすべきことは削除|
ですre
。re
いつも|
それは構成方式のために結局性格を持つようになります。これを削除しないと、その末尾|
のために正規表現がver_in.txt
。
その後、a
現在の入力行が変数の正規表現と一致する場合は、変数をre
印刷します(ver_in.txtの最初の行が一致するとaが空であるため、空行が印刷されます。re
これが発生しないようにするには、行$0 ~ re {print a}
をから)してください$0 ~ re && a != "" {print a}
。
次に、一致するかどうかに関係なく設定しますa=$0
。
注:これは、NR==FNR {... ; next}
最初の入力ファイルを2番目と後続の入力ファイルとは異なる方法で処理するための非常に一般的なawk慣用語です。 NR
は、読んでいるすべてのファイルのグローバルラインカウンタ、FNR
現在のファイルのラインカウンタです。したがって、これはNR==FNR
最初のファイルを読んでいるという意味です。このnext
ステートメントは、次の入力行にジャンプして、残りの awk スクリプトが最初のファイルで実行されるのを防ぎます。
完全なデータサンプルを提供していないので、私は自分でテストしました。
$ cat in.txt
xxyu: JHYU_IOPI
foo
bar
この in.txt ファイルは次のとおりです。bar|foo|xxyu: JHYU_IOPI
ちなみに、awkスクリプトは正規表現マッチングを実行するため、そのre
行はin.txt
固定テキストではなく正規表現として扱われます。つまり、in.txtの正規表現特殊文字(例えば、.
など|
)をリテラル文字として扱うには、バックスラッシュでエスケープする必要があります...これを行う必要があります[
。]
元のshでも動作します。 +awkループ。
$ cat ver_in.txt
a line 1
xxyu: JHYU_IOPI
b line 3
d line 4
bar
e line 6
f line 7
foo
上記のawkスクリプトの出力:
a line 1
d line 4
f line 7
答え3
テキストを操作するためにシェルループを使用しないでください。シェルループを使用してテキストを処理するのはなぜ悪い習慣と見なされますか?。シェルを発明した人は、シェルがテキストを操作するために呼び出すawkも発明しました。
すべてのUnixシステムのすべてのシェルでawkを使用してください。
$ cat tst.awk
NR==FNR {
tgts[$0]
next
}
$0 in tgts {
if ( $0 != prevTgt ) {
print $0
prevTgt = $0
}
print prevLine
}
{ prevLine = $1 FS $2 }
$ awk -f tst.awk targets file
box_name: AIX_RUN_WATCH
insert_job: AIXstop
insert_job: AIX_start
元の答え:
awk '
BEGIN { RS=""; FS="\n" }
$2 != prev {
print $2
prev = $2
}
{ print $1 }
' file
ght: ertyjk
xxx: rtyuiol
xxx: ertyuikl_fghjk
xxx: qwertyujkl
xxx: rtyuiol_123
ght: YUIOPO
xxx: rtyuiol
xxx: rtyuiopfghj
xxx: dfghjkvbnm
xxx: qzdfghnbvfgh
xxx: qsxcvghuiokmnhgf
バラよりhttps://www.gnu.org/software/gawk/manual/gawk.html#Multiple-LineRSをnullに設定する方法を学ぶ複数行のレコードを処理してFSを改行に設定すると、そのレコードの各フィールドは完全な行なので、データは空行で区切られたレコードとして処理され、各レコードには2つのデータ行が含まれますになります。
どの行を印刷する必要があるかを示す別のght行ファイルがあると述べました。これは、印刷しない他のブロックがあることを意味します。そのようなファイルがある場合は、次のようになります。
$ cat targets
ght: ertyjk
ght: YUIOPO
そして、他の入力ファイルには上記とght:
一致しないいくつかの行が含まれています。たとえば、ght: whatever
以下の変更された入力ファイルのブロックを参照してください。
$ cat file
xxx: rtyuiol
ght: ertyjk
xxx: ertyuikl_fghjk
ght: ertyjk
xxx: qwertyujkl
ght: ertyjk
xxx: rtyuiol_123
ght: ertyjk
xxx: foo
ght: whatever
xxx: bar
ght: whatever
xxx: rtyuiol
ght: YUIOPO
xxx: rtyuiopfghj
ght: YUIOPO
xxx: dfghjkvbnm
ght: YUIOPO
xxx: qzdfghnbvfgh
ght: YUIOPO
xxx: qsxcvghuiokmnhgf
ght: YUIOPO
これにより、上記のコードは次のように更新されます。
awk '
BEGIN { FS="\n" }
NR==FNR {
tgts[$0]
next
}
$2 != prev {
if ( inTgts = ($2 in tgts) ) {
print $2
}
prev = $2
}
inTgts { print $1 }
' targets RS='' file
ght: ertyjk
xxx: rtyuiol
xxx: ertyuikl_fghjk
xxx: qwertyujkl
xxx: rtyuiol_123
ght: YUIOPO
xxx: rtyuiol
xxx: rtyuiopfghj
xxx: dfghjkvbnm
xxx: qzdfghnbvfgh
xxx: qsxcvghuiokmnhgf