次のファイルがあります。
ファイル1:
0/28
7200/11
14400/11
21584/28
21600/11
28800/28
36000/11
36000/28
43200/11
43200/28
50400/11
57600/11
79200/28
左部分(/前)には秒単位の時間があり、右部分には秒単位のパラメータ値があります。
今、次のような別のファイルがあります。
ファイル2:
0 14
0 15
0 20
0 28
7200 11
7200 14
7200 15
2番目のファイルからFILE1の共通値を削除したいと思います。たとえば、FILE2から削除する必要があります。
0 28
7200 11
残りの行は変更せずに残します。
FILE1の各行に対してbashスクリプトでforループを使用してから、FILE2でその行を検索したいがパターンを認識できません。 awkでsubstrを使用しようとすると、時間の数が等しくないため動作しません(0は1桁、7200は4桁)。
FILE1を読み取るには、次の操作を行います。
IFS=$'\n' read -d '' -r -a X < ./FILE1.csv
for ループを作成するには、次のようにします。
for x in "${X[@]}"
do
gawk -i inplace -v var=${x} '{...}' FILE2.csv
done
また、FILE1を次に変換することを検討しています。
0 28
7200 11
14400 11
21584 28
21600 11
28800 28
36000 11
36000 28
43200 11
43200 28
50400 11
57600 11
79200 28
デフォルトでは2つの列がありますが、上記で使用したforとvarを使用して2つ以上の列がある場合は機能しません。 2番目のアプローチはより良いと思いますが、各列を個別に処理する方法がわかりません。
編集する:
FILE1が次の場合:
0 28
7200 11
14400 11
21584 28
21600 11
28800 28
36000 11
36000 28
43200 11
43200 28
50400 11
57600 11
79200 28
FILE2は次のようになります。
0 14 2 19
0 15 157 67
0 20 28 57
0 28 25 67
7200 11 88 14
7200 14 34 247
7200 15 364 14
答え1
使用awk
:
awk 'NR==FNR { sec[$1, $2]; next } !($1, $2) in sec' FS='/' file1 FS=' ' file2
0 14
0 15
0 20
7200 14
7200 15
これFS
(F生産するSeerator) は、対応するファイルの前の各入力ファイルのフィールド区切り文字を定義します。
答え2
最後の追加の質問に答えるには:
$ join -v 2 <(sed 's/ /:/' file1) <(sed 's/ /:/' file2) | sed 's/:/ /'
0 14 2 19
0 15 157 67
0 20 28 57
7200 14 34 247
7200 15 364 14
この答えの他の変形と同様にjoin
(答えを提供します。オリジナル質問)、これは結合キーが空白のない単一の文字列であることを確認し、2番目のファイルで結合キーが最初のファイルのエントリと一致しない行を選択します。
これは、ファイルが同じ方法でソートされる必要があるという同じ仮定を作成します。join
一度に2行だけがメモリに保持されるため、ファイル内grep
のすべてのエントリをメモリに保持する必要がある他のソリューションと比較して、同じ利点があります。
元のファイルfile1
とfile2
質問を使用して、tr
最初のファイルを2番目のファイルと同じ形式にすぐに変換し、変更されたデータを一連の行として使用して2番目のファイルから削除します。
$ grep -v -x -F -f <(tr '/' ' ' <file1) file2
0 14
0 15
0 20
7200 14
7200 15
ここで、ユーティリティは、変換された行と同じ行をgrep
フィルタリング(削除、除外)するために使用されます。file2
file1
この-x
オプションは(通常の部分文字列一致ではなく)完全行一致を強制し、パターンを正規表現ではなく固定文字列として-F
使用します。grep
この-f
オプションは、ユーティリティが指定されたファイルからパターン(プロセス置換)を読み取り、その行が一致するように一般的な-v
一致の意味を逆にするように指示します。確かに出力が一致します。
また、あなたの質問のいくつかのテキストに関連しています。
より効率的なアプローチはを使用することです。規模が大きいjoin
場合は良い考えかもしれません。file1
大きな入力の場合を使用するよりもはるかに速いと予想されますgrep
。
以下は、両方のファイルが同じ方法でソートされていると仮定し、2番目のファイルを最初のファイルと同じ形式(スペースをスラッシュに置き換えます)に変換して、空白のない行を生成します。変換方法では、デフォルトではjoin
スペースを区切り文字として使用し、スペースで区切られた最初のフィールドだけでなく行全体も考慮する必要があります。
$ join -v 2 file1 <(tr ' ' '/' <file2) | tr '/' ' '
0 14
0 15
0 20
7200 14
7200 15
これにより、2つのデータセット間でリレーショナルJOIN操作が実行され、2番目の入力で一致しない行が変換されたjoin
2番目のファイルに返されます。最終結果としてスペースで区切られたデータが必要なので、末尾のスラッシュをスペースで置き換えます。
これはいつでもメモリに2行以上のデータを保持しませんが、バリアントは最初のファイルgrep
の内容全体をメモリに保持し、2番目のファイルの各行に対して2番目のファイルの各行をテストする必要があります。ラインファイル。
答え3
この問題はShell Loopを使用して解決します。
cat FILE2 | tr " " / | \
while read i;do
cat -n FILE1| grep -w "$i" | awk '{print $1}' | \
while read j;do
sed -i "${j}d" FILE1
done
done
答え4
SUBSEP
以下は、ファジー、フィールドの繰り返し、ファイルの事前ソート、または列/フィールドの数のプリセットを必要としないソリューションです。
mawk -v \_=testfile_001.txt -F/ '
BEGIN {
while(getline<_) {
__[$!(NF=NF)]
}
_*=close(_)*(FS="^$") } _^($_ in __)' testfile_002.txt
0 14
0 15
0 20
7200 14
7200 15
- 今
FS="^$"
設定を実装しました。2番目のファイル行範囲のマッチングを実行するので、splitting fields
時間が無駄になるので、はるかに高速です。
gawk 5.1.1
(ロゴを含む-c/-P
)mawk 1.3.4
、、、mawk 1.9.9.6
および作業のテストと検証が行われました。macos nawk
- The 4Chan Teller