複数のファイルからいくつかの情報を抽出し、csvタイプファイルを作成しようとしています。今までファイルの一部を抽出して作成しましたが、各出力の間にカンマを追加するか、最後から改行を削除する方法がわかりません。
#!/bin/bash
for file in folder/*.txt do
grep 'sometext:' $file | sed '/^.*:\s*//' >> list.txt
#doing simliar stuff with other lines in the current file
done
改行削除を試しましたが、echo -n
有用な情報は返されませんでした。
コードの役割:
フォルダ内の各ファイルに対して、いくつかのパターン(など)で始まる行を見つけ、残りの行sometext:
とsomeothertext:
a,
をlist.txt
。
フォルダ内のファイルコンテンツの例:
randomtext: ...
sometext: Hello
randomtext: ...
someothertext: World
somedifferenttext: !
randomtext:
出力ファイルに1行が生成されます。Hello,World,!,
ベストアンサー1
まあ、最初からループを使用しないでくださいfor
!これは非常に非効率的です。grep
すべてのファイル名を一度に指定してください。
grep 'sometext:' folder/*.txt
ただし、この場合は代わりにawk
を使用してgrep
テストするために入力ファイルの10個のコピーを作成しました。
$ awk '{
if($1~/sometext|someothertext|somedifferenttext/){
printf "%s,",$2
}
if(FNR==1 && NR>1){
print ""
}
}
END{ print "" }' folder/*txt
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
説明する
awk
入力を 1 行ずつ読み込み、余白の各行-F
(デフォルトで変更可能)をフィールドに分割するスクリプト言語です。最初のフィールドはで$1
、2番目のフィールドは$2
このようになります。
if($1~/sometext|someothertext|somedifferenttext/){
:最初のフィールドがsometext
orsomeothertext
またはと一致する場合somedifferenttext
。この項目も一致しますfoosometext
。正確な一致を制限するには、次のように変更してください。if($1=="sometext:" || $1=="someothertext:" || $1=="somedifferenttext:"){
printf "%s,",$2
:上記の条件が満たされたら、2番目のフィールドを印刷し、その後にカンマを入力します。if(FNR==1 && NR>1){ print "" }
:NR
現在の入力行番号とFNR
現在のファイルの行番号。したがって、ファイルに行番号1があるたびに改行が印刷されます(print
awk呼び出しはデフォルトで改行を追加するため、何も印刷しないのは改行を印刷するのと同じです)。ただし、処理された合計行数が1の場合は必要です。ティー。つまり、新しいファイルを読み始めるたびに改行文字が印刷されます。END{ print "" }'
:すべてのファイルを処理した後、改行文字も印刷します。
これは、1行に2つのフィールドしかないと仮定します。行全体を印刷する必要がある場合は、次のものを使用できます(正確な一致のみを印刷するバージョンとして説明されています)。
awk '{
if($1=="sometext:" ||
$1=="someothertext:" ||
$1=="somedifferenttext:"){
$1="";
printf "%s,",$0
}
if(FNR==1 && NR>1){print ""}
}END{print ""}' folder/*txt | sed 's/^ //'
$0
違いは、(フル行)を代わりに使用し、印刷する前に空の文字列に$2
設定することです$1
。これにより、先頭に余分なスペースが印刷されます(空白はまだフィールドと見なされるため)、それを削除するために渡します$1
。sed
または、Perlですべての操作を実行できます。
$ perl -lane '
if($F[0]=~/(sometext|someothertext|somedifferenttext):/){
push @k,@F[1..$#F]
}
if(eof){
print join ",", @k; @k=();
}' folder/file*
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
Hello,World,!
または末尾があるかもしれません,
。
$ perl -lane '
if($F[0]=~/^(sometext|someothertext|somedifferenttext):$/){
push @k,@F[1..$#F]
}
if(eof){
print join ",", @k , ""; @k=();
}' folder/file*
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
説明する
ここでの基本的なアイデアは同じです。 Perlのスイッチは、各入力ラインを配列に分割する-a
ように動作します。次に、配列の最初の要素が必須文字列の1つである場合、残りのフィールド()が配列に追加されます。ファイルの終わり()に達すると、配列の内容をコンマで連結し、結果の文字列を印刷します。awk
@F
@F[1..$#F]
@k
if(eof)
@k
最後に、試してみるように行う方法があります(GNU仮定grep
)。
$ for f in folder/*; do
grep -hoP '^(sometext|someothertext|somedifferenttext): \K.*' "$f" |
perl -pe 's/\n/,/; END{print "\n"}';
done
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,
Hello,World,!,