Como mover uma linha de um arquivo para outro arquivo com base na correspondência de padrões?

1

Eu quero mover linhas de um arquivo de texto para outro arquivo de texto. Essas linhas contêm uma palavra que começa com um sublinhado. Esta palavra está localizada no campo sexto das linhas; campos são separados por barras. Por exemplo, mova linhas contendo _Nokia no sexto campo, no arquivo de entrada de amostra, abaixo.

Apple/One-plus/Samsung/Mi/Sony/_Nokia/
Apple/One-plus/Samsung/Mi/Lenovo/_Nokia/
Apple/One-plus/Samsung/Mi/HTC/OPPO/

Eu tentei mover linhas correspondentes, com uma expressão regular, usando grep , mas isso não funciona.

$ grep -F 'Apple/One-plus/Samsung/Mi/^[a-zA-Z]([\w -]*[a-zA-Z])?$/_Nokia/' match.txt >file1.txt
$ grep -F -v "Apple/One-plus/Samsung/Mi/^[a-zA-Z]([\w -]*[a-zA-Z])?$/_Nokia/" match.txt \
    > match.txt.tmp && mv match.txt.tmp match

Saída esperada

$ cat file1.txt
Apple/One-plus/Samsung/Mi/Sony/_Nokia/
Apple/One-plus/Samsung/Mi/Lenovo/_Nokia/
$ cat match
Apple/One-plus/Samsung/Mi/HTC/OPPO/

Como mover uma linha de um arquivo para outro arquivo com base na correspondência de padrões?

    
por sam 07.09.2018 / 01:42

3 respostas

0

Se você tem uma versão recente do GNU awk ( gawk ) você poderia fazer

awk -i inplace -F'/' '$7 == "_f" {print > "otherfile"; next} 1' file

Se o seu awk não suporta a opção -i inplace , então você pode fazer a mesma coisa, mas redirecionar a saída para um arquivo temporário e depois renomeá-lo.

    
por 07.09.2018 / 02:52
0

edição original

Uma expressão regular não pode ser especificada com a opção -F referente a grep . Há outro problema em relação à expressão regular. Se o caractere ^ for usado como uma âncora para corresponder ao início de uma linha, ele deverá ser o primeiro caractere da expressão regular.

prompt% cp -v input input.back
prompt% grep -e "$regex" input.back > output
prompt% grep -v "$regex" input.back > input

Expressão regular: o autor original não forneceu uma contribuição concreta, portanto, é difícil encontrar uma expressão regular adequada.

Editar: finalmente, o autor original forneceu um arquivo de entrada de amostra.

Apple/One-plus/Samsung/Mi/Sony/_Nokia/
Apple/One-plus/Samsung/Mi/Lenovo/_Nokia/
Apple/One-plus/Samsung/Mi/HTC/OPPO/

Expressão regular: regex

regex='\([-[:alpha:]]\+\/\)\{5\}_Nokia\/'

Soluções alternativas

Estas soluções similares não são recomendadas para iniciantes que nunca leram o manual do sed.

sed -n "/$regex/p;/$regex/d;w input" input.back > output

Grosso modo, as linhas que correspondem à expressão regular são salvas no arquivo output , então, elas são excluídas do buffer de recepção correspondente e o conteúdo do buffer é gravado no arquivo input .

sed -i.back -e "/$regex/w output" -e "/$regex/d" input

Esses comandos têm diferenças sutis, mas o segundo é mais conveniente.

    
por 07.09.2018 / 17:41
0

Como sobre essa proposição? Esta é uma proposta menos concisa do que a @ resposta da steeldriver , no entanto, é uma solução progressiva (passo a passo).

$ cut -d/ -f7 data.txt  | grep -n _f | cut -d: -f 1 | xargs -i sed -n {}p data.txt > otherfile.txt
  • _f é o padrão quando a correspondência é criada para o outro arquivo.

  • data.txt é o seu arquivo

  • / é seu delimitador

Se isso funcionar, faça um comm para descobrir o que deve permanecer no arquivo original.

$ comm -23 data.txt otherfile.txt > remainder.txt

remainder.txt é seu data.txt com os bits removidos.

    
por 07.09.2018 / 03:19