Como posso excluir a 5ª palavra de cada linha de um arquivo?

13

Quero excluir a 5ª palavra de cada linha em um arquivo.

O conteúdo atual do arquivo:

File is not updated or and will be removed  
System will shut down f within 10 seconds  
Please save your work 55 or copy to other location  
Kindly cooperate with us D  

Saída esperada:

File is not updated and will be removed  
System will shut down within 10 seconds  
Please save your work or copy to other location  
Kindly cooperate with us
pmaipmui
fonte

Respostas:

31

Que tal cut:

$ cut -d' ' -f1-4,6- file.txt 
File is not updated and will be removed  
System will shut down within 10 seconds  
Please save your work or copy to other location  
Kindly cooperate with us
  • -d' ' define o delimitador como espaço

  • -f1-4,6- seleciona o primeiro ao quarto campo (palavra), deixando o 5º e depois continua a impressão do 6º para o restante.

heemail
fonte
11

Uma solução com cut:

cut -d ' ' -f1-4 -f6- FILE
fd0
fonte
Múltipla -fnão é suportado no meu cut(GNU), pelo menos ..
heemayl
Suportado no corte BSD, mas eu gosto mais da sua resposta que a minha.
Fd0
1
Se é GNU corte, você tem a --complementbandeira de simplificar as coisas: cut --complement -d ' ' -f5. Lembre-se de redirecionar a saída para um novo arquivo e depois mvsobre o original.
Toby Speight
6

awk: remova o 5º campo

awk '{for (i=5; i<NF; i++) $i = $(i+1); NF--};1' file

Se você deseja salvar o arquivo no local: /programming//q/16529716/7552

Você pode simplesmente apagar o conteúdo do 5º campo, mas isso deixa 2 separadores de campo de saída consecutivos:

awk '{$5 = ""};1' file
Glenn Jackman
fonte
a ressalva aqui é que a alteração do valor de qualquer campo no awk tem o efeito colateral de reescrever todo o "$ 0" com apenas 1 separador entre cada campo. deve ser levado em conta se você queria manter qualquer alinhamento (a menos GNU awk tem uma opção evitar este awk regulares / nawk irá recalcular $ 0?)
Olivier Dulac
Nos dois casos, você reformata a linha com um único separador. Se houver 2 espaço ou espaço + tabulação em um separador, o resultado será um único espaço no local. Esperançosamente, isso é bom para a maior parte do texto.
NeronLeVelu
4

Com o POSIX sed:

sed -e 's/[^[:alnum:]_][[:alnum:]_][[:alnum:]_]*//4' <file
cuonglm
fonte
por que limitar a classe a: alnum: e _ e mais nada então :blank:ou :space:?
NeronLeVelu 16/07/2015
@NeronLeVelu: Isso depende de como você define o que faz uma palavra.
cuonglm
@mikeserv; Boa pegada! Eu atualizei minha resposta.
18715 cuicklm
Para que \(serve o grupo de captura \)?
Mikeerv
@ MikeServ: minha digitação incorreta, eu apenas tentei algumas maneiras de manter o delimitador.
18714 cu Cullm
2

A Glenn ofereceu uma solução equivalente a

awk '{$ 5 = ""; arquivo print} '

Como ele e outros salientaram, esse

  1. retira espaços em branco à esquerda e à esquerda de todas as linhas,
  2. comprime cada sequência de espaços em branco (espaços e / ou tabulações) em um único espaço e
  3. deixa dois espaços entre a quarta e as seis palavras.

Um truque para corrigir o terceiro problema é

awk '{$ 5 = ""; print} ' arquivo | sed / s / / /

Isso ainda deixará um ou mais espaços adicionados no final de qualquer linha que contenha cinco ou menos palavras. Se você conseguir identificar uma palavra que nunca aparecerá na entrada,

awk '{$ 5 = "unicórnio"; print} ' arquivo | sed 's / * unicórnio //'

vai lidar com isso mesmo (mas ainda deixa os problemas 1 e 2).

Scott
fonte
2
 sed 's/^\(\([[:blank:]]*[^[:blank:]]\{1,\}\)\{4\}\)[[:blank:]]*[^[:blank:]]*/\1/' YourFile > Output.txt
  • posix sed com base no separador de espaço / tabulação (meta classe [: blank:]])
  • mantenha o espaço a seguir após a quinta palavra, mas remova-o antes

Um mais robusto (sed leva o maior padrão possível e o padrão *pode faltar a separação ou a palavra na primeira versão), mas uma versão um pouco mais longa

sed 's/^\([[:blank:]]*\([^[:blank:]]\{1,\}[[:blank:]]\{1,\}\)\{4\}\[^[:blank:]]\{1,\}/\1/' YourFile > Output.txt
NeronLeVelu
fonte
1
sed 's/[^[:blank:]]*//5'
Mikeerv
@ mikeserv, isso manterá os dois separadores circundantes, sed 's/[[:blank:]*[^[:blank:]]*//5'é melhor. Muito bom ponto. Eu suspeitava que sed tomar cada caractere único como uma entidade, mas é preciso maior padrão unbreaked como entidade
NeronLeVelu
sed 's/[[:blank:]][^[:blank:]]*//4'removerá completamente o 5º campo.
mikeserv
@mikeserv Assumindo que não há espaço está começando na linha (como na amostra)
NeronLeVelu
Nesse caso, sim, acho que você está certo. Normalmente, tal coisa seria um campo nulo e o comportamento estaria correto. Neste caso você deve fazer como @cuonglm fez e garantir que você fazer referência a uma palavra de cada vez como sed 's/[[:blank:]][^[:blank:]][^[:blank:]]*//4', ou, w / GNU / BSD / toybox seds: sed -E 's/[[:blank:]][^[:blank:]]+//4'.
mikeserv
1

Perl.

perl -ne 'print $_ =~ /^(\w+ +\w+ +\w+ +\w+ +)\w+ (.*)/,"\n"' file
Steve
fonte
1

Outra possibilidade, assumindo o corte do GNU:

cut -d' ' -f5 --complement file.txt
Trauma Digital
fonte
-1

Usando Perl> 5.10 (e produzindo com êxito todas as linhas: 0)): -

perl -nE '/^((\w+ +){4})\w+ *(.*)/; say $1.$3' file
Medlock Perlman
fonte