txtファイル内容を変数とした繰り返し処理でawkを行いたい
環境はWindows Ubuntu ver.18.04.2 Linuxです。Linuxに触れて数日の初心者です。
下記の冗長なbashスクリプトを実装しました。
本来実装したいことは、
(1)awk内で繰り返し処理をするとき、別途ファイルを参照すること。
(2)awkで繰り返し処理をするとき、出力を再度入力にすること。です。
具体的に処理した下記コード欄を参考に概要は、
入力はタブ区切りtxtで、あるフィールド(f2)に情報が詰め込まれています。
ループ処理で別途切り出し用txtの列内容(1列目)を変数にしてawkのmatchで文字列の抜き取り、組み込み関数 (RSTART, RLENGTH)でf2の単語を入力ファイルの最後列(f101)に付け加え、タブ区切りtxtで出力(out.txt)する。
出力したtxtをmvでinput.txtに変更後awkの再入力とし、別途切り出し用txtの内容(2列目)でループ処理を続ける、というものです。
以下に例として、入力ファイル、別途切り出し用txtファイル、bashコードを示します。
使用するファイル(例)
#入力ファイルinput.txt(タブ区切りtxt)
f1 f2 ... f100
1 aaa=1.0;bbb=0.500;ccc=0.200 ... def
2 aaa=0.800;bbb=0.750;ccc=0.800 ... ghi
3 ... jkl
…
100 aaa=0.004;bbb=0.000;ccc=0.008 ... xxx
#別途切り出し用ファイルregex.txt (スペース区切りtxt)
r1 regex1 val1 val2
r2 regex2 val3 val4
r3 regex3 val5 val6
…
r10 regex10 valX valY
実装済の冗長ソースコード
awkの外側の外部ファイル参照によるwhile read文で繰り返し処理を行っている。
while read key regex val1 val2 ; do
cat ./input.txt | awk '
BEGIN{
FS = "\t"
OFS = "\t"
}
NR==1{$0,'"$key"'}
NR>1{
if(match($2, /'"$regex"'/)){
print $0,substr($2, RSTART + '"$val1"', RLENGTH - '"$val2"')
}else{print $0,"0"}
}
'>./out.txt #同名の./input.txtだと処理がうまくいかない(空白のテキストができる)
mv ./out.txt ./input.txt #処理に時間がかかるがout.txtとして1度出力し、mvで名前を変更した。
done < ./regex.txt
実装したいこと
awkの中で別途切り出し用txtを変数に入れ繰り返し処理をする。そうすることで、下記のawk再入力問題は解決できる?気がするため。
もしくはawkの外側のwhile leadで繰り返しながら、awkの出力をそのまま再入力にする。
awkでできないなら、触れたことがありませんがperl等でも構いません。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+2
私だったらこんな感じにします。
ちゃんとテストしてないので細かいミスがあるかもしれません。あくまで雰囲気を示します。
# test.awk
BEGIN{
n=0
while((getline < "regex.txt")>0){
regexp[n]=$2; val1[n]=$3; val2[n]=$4;
n++
}
FS = "\t"
OFS = "\t"
}
NR==1{$0,'"$key"'}
NR>1{
if(match($8, regexp[i])){
for(i=0; i<n; i++){
$0 = $0 substr($2, RSTART + val1[i], RLENGTH - val2[i])
}
print
}
}
$ awk -f test.awk input.txt
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
手抜き解
mv を無くすだけでよければ
f0=./input.txt
f1=./work.txt
while read key regex val1 val2 ; do
cat $f0 | awk ...
:
}
'> $f1
f=$f0
f0=$f1
f1=$f
done < ./regex.txt
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
テスト可能なデータが書かれてないので、テストしてませんが、こんな感じで。
input.txt
の方を全部変数に読み込んで、regex.txt
の方を読みながら書き換えていきます。
awk '
FS=="\t" && NR==1 {head=$0;next}
FS=="\t" {all[NR]=$0;a[NR]=$2;N=NR;next}
{ key=$1; regex=$2; val1=$3; val2=$4
head=head "\t" key
for(i=2;i<=N;i++){
if(match(a[i],regex)){
all[i]=all[i] "\t" substr(a[i],RSTART+val1,RLENGTH-val2)
}
}
}
END{
print head
for(i=2;i<=N;i++){
print all[i]
}
}
' FS="\t" input.txt FS=" " regex.txt
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
regex.txt の内容が変わらないのなら、それから awk スクリプトを生成しておく方法も
awk1.tpl
BEGIN{
FS = "\t"
OFS = "\t"
getline
print $0,"key"
}
awk2.tpl
if(match($2, /regex/)) {
line = line,substr($2, RSTART + val1, RLENGTH - val2)
}
awk スクリプト生成
sed 's/key/`cut -f 1 regex.txt | xargs | tr " " "\t"`/' awk1.tpl >hoge.awk
echo '{' >>hoge.awk
echo ' line = $0' >>hoge.awk
cat regex.txt | \
while read key regex val1 val2
do
sed 's/regex/'$regex'/;s/val1/'$val1'/;s/val2/'$val2'/' awk2.tpl >>hoge.awk
done
echo ' print line' >>hoge.awk
echo '}' >>hoge.awk
実行はこんな感じで
cat input.txt | awk -f hoge.awk >result.txt
※動かしてないので考え方だけ参考にしてください。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.33%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
質問への追記・修正、ベストアンサー選択の依頼
takasima20
2020/02/13 20:27
mv を無くして awk 内で完結したいってこと? あと、いまのままだとループごとに1行づつ減るよね?
s-o
2020/02/13 20:41
>mv を無くして awk 内で完結したいってこと?
その通りです。省きましたが入力ファイルは複数あるため、無駄な処理(mv)をなくしたいです。
>いまのままだとループごとに1行づつ減るよね?
NR>1の部分でしょうか?省きましたが、NR==1の処理も行っております。申し訳ございません。軽く修正します。
takasima20
2020/02/14 00:16
ついでに… match しなかった場合もなんか入れとかないと、項目数的に整合性とれなさそげ。
s-o
2020/02/14 09:20
ifのelse処理もあえて省いていました。申し訳ございません。
本来の質問内容に該当する部分を抽出して示していました。
念のため修正します。