ファイルfile1.txtには、次のような行が含まれています。
/api/purchase/<hash>/index.html
例えば:
/api/purchase/12ab09f46/index.html
ファイルfile2.csvには、次のような行が含まれています。
<hash>,timestamp,ip_address
例えば:
12ab09f46,20150812235200,22.231.113.64
a77b3ff22,20150812235959,194.66.82.11
File2.csvをフィルタリングして、file1.txtにもハッシュの値が存在するすべての行を削除します。それは言うことです:
cat file1.txt | extract <hash> | sed '/<hash>/d' file2.csv
またはこのようなもの。
簡単なはずですが、うまく動かないようです。
誰もがこのタスクのための作業パイプラインを提供できますか?
cut -d / -f 4 file1.txt | paste -sd '|' | xargs -I{} grep -v -E {} file2.csv
説明:
cut -d / -f 4 file1.txt
は最初のファイルからハッシュを選択します
paste -sd '|'
は、すべてのハッシュを正規表現exに結合します。 H1|H2|H3
xargs -I{} grep -v -E {} file2.csv
は前のパターンを引数としてgrepを呼び出し、xargsは{}
をSTDIN
の内容に置き換えます
paste
がない場合は、tr "\\n" "|" | sed 's/|$//'
に置き換えることができます。
可能なawk
ソリューション:
awk 'NR == FNR { x[$4] = 1; next; } { if (!($1 in x)) print $0; }' FS="/" file1.txt FS="," file2.txt
最初にFS
(フィールドセパレータ) "/"を使用してfile1.txt
を読み取り、必要なハッシュであるフィールド$4
からのキー値で配列xを作成します。次に、2番目のファイルfile2.txt
を設定してFS
を,
に設定し、フィールド$1
の値が配列x
のキーとして存在しないかどうかと、印刷しません。
コメントで提案されているのと同じより慣用的なものは次のようになります:
awk 'NR == FNR { x[$4] = 1; next; } !($1 in x)' FS="/" file1.txt FS="," file2.txt
GNU sedの場合
sed -z 's%.*/\([^/]*\)/index.html\n%\1\\|%g;s%^%/%;s%\\|$%/d%' file1.csv |
sed -f - file2.csv
ここでfirstsed/12ab09f46\|a77b3ff22\|..../d
のようなsed-command-formatでハッシュのリストを生成し、それをnextsed-script入力から上記のコマンドを読み取るため、-f -
オプション。
grepと同じ
grep -oP '[^/]*(?=/index.html$)' file1.csv | grep -Fvf - file2.csv
またはPerl-expresionsなし:
grep -o '[^/]*/index.html$' file1.csv |
grep -o '^[^/]*' |
grep -Fvf - file2.csv
cut:
cut -d/ -f4 file1.csv | grep -Fvf - file2.csv
#!/bin/bash
cut -d, -f1 file2 | while read key ; do
#check for appearance in file1 with successful grep:
#exit status is 0 if pattern is found, only search for at least 1
#appearance -> to speed it up
if [[ $(grep -m 1 "/$key/" file1) ]] ; then
sed "/^$key,/d" -i file2
#note that we are gradually overwriting file2 (-i option),
#so make a backup!
fi
done
検索文字列は/$key/
と^$key,
であり、結果が2つのスラッシュの間にある(ファイル1)か、行の最初のエントリになり、その後にコンマが続く(ファイル2)ことに注意してください。これは、キーが次のように見える場合に安全になるはずです
a,values
a1,values
ファイル2など
/api/../a1/../
/api/../a/../
ファイル1
私は次のライナーを試してみました、そしてそれは仕事をするようです:
for i in `cat file1.txt | awk -F"/" '{print $4}'`; do echo "\n $i" ; sed -ri "/^$i,/d" file2.csv ; done
最初に-riを-reに置き換えてテストしてください。 -re予行演習を行い、問題がなければ-riで実行できます。
Gabriele Lanaの回答 に加えて、標準入力からコンテンツを読み取るには、BSD pasteコマンドでダッシュを指定する必要があることに注意してください。
1つ以上の入力ファイルに「-」が指定されている場合、標準入力が使用されます。標準入力は、「-」のインスタンスごとに1行ずつ循環的に読み取られます。
最終的には以下のように変更する必要があります
cut -d / -f 4 file1.txt | paste -sd '|' - | xargs -I{} grep -v -E {} file2.csv