remove linhas no arquivo 1 do arquivo 2

0

Eu tenho um texto que inclui linhas que eu gostaria de excluir do meu texto original.

como exemplo

Texto original

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

Linhas de inclusão de texto a serem removidas

12,12
99999999999999999,19,1999,199

Resultado esperado

11
111111111111111111,111111111,11

qual é a melhor solução para esse caso?

    
por αԋɱҽԃ αмєяιcαη 04.12.2017 / 03:44

2 respostas

0

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
    
por 04.12.2017 / 04:02
0

Eu consegui o resultado mencionado usando este one-liner awk

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

O comando a seguir exclui o conteúdo do arquivo2 do arquivo1

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

Saída:

11
111111111111111111,111111111,11
    
por 04.12.2017 / 06:34