ファイルがあり、ファイル内の複数のファイル名を探しています。検索テキストの例intl_reg.jcl
。見つけたら、その上に3行のテキストをインポートする必要があります。たとえば、以下はファイルの4行です。 「残高登録された留学生」という説明 前のテキストは常にCHOICEで、その後に説明が続きます。
CHOICE List registered international students with balances
SHORTCUT 8
PROCESS CHDIR /d3/locban/arsys
PROCESS CMD ksh /d3/locban/arsys/intl_reg.jcl
次のようにリストするには、grepコマンドが必要です。
intl_reg.jcl registered international students with balances
答え1
使用幸せ(以前のPerl_6)
~$ raku -e 'my @a; for lines() {
if @a.elems == 4 { @a.push($_); @a.shift }
elsif @a.elems < 4 { @a.push($_) };
if .match( /intl_reg\.jcl/ ) and @a.elems == 4 {
say $<>.Str, @a[0].split( /<?after List>/ ).[1] };
};' file
つまり、@a
配列を宣言してlines
コマンドラインから読み込みます。入力は4になるまで配列に追加され、push
最大サイズを4つの要素に維持するために最初の要素が削除されます。@a
elems
shift
配列に4つの要素が含まれていることmatch
が確認されたら、一致する変数(と同じ)を印刷し、3行前に記録された行を印刷して、必要な文字列を適切に返します。and
$<>
$<>
$/
split
入力例:
A CHOICE List registered international students with balances
A SHORTCUT 8
A PROCESS CHDIR /d3/locban/arsys
A PROCESS CMD ksh /d3/locban/arsys/intl_reg.jcl
B CHOICE List registered international students with balances
B SHORTCUT 8
B PROCESS CHDIR /d3/locban/arsys
B PROCESS CMD ksh /d3/locban/arsys/intl_reg.jcl
出力例:
intl_reg.jcl registered international students with balances
intl_reg.jcl registered international students with balances
答え2
次のawk
プログラムが動作します。
オプション1:デュアルチャンネル
awk -v d=3 -v s="intl_reg.jcl" '(NR==FNR) && index($0,s){i=FNR;nextfile}
FNR==(i-d){printf "%s\t%s\n",s,$0; exit}' input.txt input.txt
ここでは、入力ファイルを2回指定して2回処理するようにします。検索する文字列がawk
変数として渡されs
、距離がawk
変数として渡されますd
。
- 最初のステップでは、
NR
グローバル行カウンタはFNR
ファイルごとの行カウンタと同じであり、各行に文字列があるかどうかを確認します。見つかった場合、行番号は変数に保存され、i
実行はすぐに次のファイル(=同じファイルの次の繰り返し)にジャンプします。 - 2番目のパスでは、プログラムは現在の行番号が以前
d
に認識されたパターン発生回数(に保存されている)より小さいことを確認しますi
。その行が見つかると、検索文字列とともに印刷され、プログラムが終了します。ファイル部分の残りの部分をアイドル状態に循環しないようにします。
オプション2:片道
プロセスを高速化してファイルに再度アクセスできない場合(パイプなど)、バッファリングを含むシングルパスソリューションを使用することもできます。この場合、特定の長さの FIFO バッファが必要です。つまり、d
大きすぎると実用的ではありません(ただし問題になる場合はほとんどありません)。d
awk -v d=3 -v s="intl_reg.jcl" 'FNR>1{for (j=d;j>0;j--) {buf[j]=buf[j-1]}; buf[0]=$0}
FNR>d && match($0,s) {printf "%s\t%s\n",s,buf[d];exit}' input.txt
buf
d+1
これにより、バッファの内容が各新しい行で「上に移動」し、現在の行は常に最後の数行でバッファを埋めますbuf[0]
。検索文字列が見つかると、行の内容が印刷されますbuf[d]
。これはd
現在の行の前の行です。今回もパフォーマンス上の理由でプログラムは直ちに終了します。
答え3
match=intl_reg.jcl
tac {file} |
sed -n "/$match/ { n; n; n; s/^CHOICE/$match/p }"
正規表現演算子を$match
含めたり含めないでください。/
(これは.
実際にはワイルドカードなので、このルールをすぐに破棄してください。これは問題になる可能性があります。)
答え4
awkを使用してください。
$ awk -v t='intl_reg.jcl' '{a[NR%4]=$0} index($0,t){$0=a[(NR-3)%4]; $1=$2=""; print t $0}' file
intl_reg.jcl registered international students with balances