Aqui está um usuário de uma só linha grep
:
grep -Fxv -f file1.txt file2.txt
Este comando gera as linhas em file1.txt
que não estão em file2.txt
- na ordem em que aparecem.
Se você não se importa com a preservação da ordem, você também pode usar o comando comm
:
comm -23 <(sort file1.txt) <(sort file2.txt)
Este comando gera a linha em file1.txt
que não estão em file2.txt
-
na ordem classificada.
Você também pode usar um loop while para iterar as linhas do primeiro arquivo (por exemplo, file1.txt
), verificar cada linha em relação ao segundo arquivo (por exemplo, file2.txt
) usando grep
e imprimir a linha se não foi encontrado. Isso terá o efeito de produzir o texto compreendendo as linhas de file1.txt
com as linhas de file1.txt
removed. Poderia ser algo assim:
while read line; do
if ! grep -qF -- "${line}" file2.txt; then
echo "${line}";
fi;
done < file1.txt
Se você quiser gravar os resultados em um arquivo, poderá usar o redirecionamento de saída, por exemplo:
while read line; do
if ! grep -qF -- "${line}" file2.txt; then
echo "${line}";
fi;
done < file1.txt > output.txt
O mesmo vale para os comandos grep
e comm
:
grep -Fxv -f file1.txt file2.txt > output.txt
comm -23 <(sort file1.txt) <(sort file2.txt) > output.txt
NOTA: Você não pode redirecionar a saída de volta para file1.txt
. Devido à forma como o redirecionamento de saída é implementado, isso só acabará excluindo o conteúdo de file1.txt
. Para uma discussão adicional desta questão, ver, e. o seguinte post:
Se você quiser substituir o arquivo original, basta sobrescrevê-lo com o arquivo de saída, ou seja:
mv output.txt file1.txt
Você também pode transformar isso em um script. Aqui está um script usando o loop 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}"
E aqui está o mesmo script usando 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}"
Note que eu uso a função mktemp
para gerar um nome de arquivo aleatório para o arquivo de saída.
Veja como o script ficaria em ação:
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