元のテキストから削除したい行を含むテキストがあります。
例として
オリジナル
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