file2からfile1の行を削除する

file2からfile1の行を削除する

元のテキストから削除したい行を含むテキストがあります。

例として

オリジナル

11
111111111111111111,111111111,11
12,12
99999999999999999,19,1999,199

テキストには削除する行が含まれています。

12,12
99999999999999999,19,1999,199

期待される出力

11
111111111111111111,111111111,11

それでは、この状況に対する最善の解決策は何ですか?

答え1

1行のawkコードを使用して上記の結果を得ました。

$ cat file1
11
111111111111111111,111111111,11
12,12
99999999999999999,19,1999,199
$ cat file2
12,12
99999999999999999,19,1999,199

次のコマンドは、file1からfile2の内容を削除します。

awk 'NR==FNR {a[$1];next}!($1 in a ) {print $1}' file2 file1

出力:

11
111111111111111111,111111111,11

答え2

以下はシングルラインユーザーですgrep

grep -Fxv -f file1.txt file2.txt

このコマンドは、file1.txt含まれていない行が表示される順序で印刷します。file2.txt

順序の維持に興味がない場合は、次のcommコマンドを使用することもできます。

comm -23 <(sort file1.txt) <(sort file2.txt)

このコマンドは、ソートされた順序ではfile1.txtなく行を出力します。file2.txt

また、whileループを使用して最初のファイル(たとえば)の行を繰り返し、2番目のファイルfile1.txt(たとえば)とfile2.txt各行を比較してgrep見つからない場合は、その行を印刷できます。これにより、file1.txt削除されたテキスト行を含める効果がありますfile1.txt。次のように見えます。

while read line; do
    if ! grep -qF -- "${line}" file2.txt; then
        echo "${line}";
    fi;
done < file1.txt

結果をファイルに書き込むには、出力リダイレクトを使用できます。たとえば、次のようになります。

while read line; do
    if ! grep -qF -- "${line}" file2.txt; then
        echo "${line}";
    fi;
done < file1.txt > output.txt

grepコマンドも同じですcomm

grep -Fxv -f file1.txt file2.txt > output.txt
comm -23 <(sort file1.txt) <(sort file2.txt) > output.txt

メモ:file1.txt出力リダイレクトの実装方法により、出力を再リダイレクトできませんfile1.txt。この問題の詳細については、次の記事を参照してください。

元のファイルを置き換えるには、次のように出力ファイルで上書きできます。

mv output.txt file1.txt

スクリプトに変換することもできます。以下はwhileループを使用するスクリプトです。

#!/usr/bin/env bash
# removelines.sh

# Set filenames
INPUTFILE="$1"
FILTERFILE="$2"
OUTPUTFILE="$(mktemp)"

# Write the lines from INPUTFILE to OUTPUTFILE
# minus the lines from FILTERFILE
while read line; do
    if ! grep -qF -- "${line}" "${FILTERFILE}"; then
        echo "${line}";
    fi;
done < "${INPUTFILE}" > "${OUTPUTFILE}"

# Replace INPUTFILE with OUTPUTFILE
mv "${OUTPUTFILE}" "${INPUTFILE}"

これは同じスクリプトを使用していますcomm

#!/usr/bin/env bash
# removelines.sh

# Set filenames
INPUTFILE="$1"
FILTERFILE="$2"
OUTPUTFILE="$(mktemp)"

# Write the lines from INPUTFILE to OUTPUTFILE
# minus the lines from FILTERFILE
comm -23 <(sort "${INPUTFILE}") <(sort "${FILTERFILE}") > "${OUTPUTFILE}"

# Replace INPUTFILE with OUTPUTFILE
mv "${OUTPUTFILE}"

mktemp出力ファイルの任意のファイル名を生成するためにこの関数を使用することに注意してください。

スクリプトの実行時に実際に表示される様子は次のとおりです。

user@host:~$ cat <<HEREDOC > file1.txt
11
111111111111111111,111111111,11
12,12
99999999999999999,19,1999,199
HEREDOC

user@host:~$ cat <<HEREDOC > file2.txt
12,12
99999999999999999,19,1999,199
HEREDOC

user@host:~$ bash removelines.sh file1.txt file2.txt

user@host:~$ cat file1.txt
11
111111111111111111,111111111,11

関連情報