Quero deletar a última coluna de um arquivo txt, embora não saiba qual é o número da coluna é. Como eu poderia fazer isso?
Exemplo:
Entrada:
1223 1234 1323 ... 2222 123 1233 1234 1233 ... 3444 125 0000 5553 3455 ... 2334 222
E eu quero que minha saída seja :
1223 1234 1323 ... 2222 1233 1234 1233 ... 3444 0000 5553 3455 ... 2334
Comentários
Resposta
Com awk
:
awk "NF{NF-=1};1" <in >out
ou:
awk "NF{NF--};1" <in >out
ou:
awk "NF{--NF};1" <in >out
Embora pareça vodu, funciona. Existem três partes para cada um desses comandos awk.
A primeira é NF
, que é uma pré-condição para a segunda parte. NF
é uma variável que contém o número de campos em uma linha. No AWK, as coisas são verdadeiras se “não forem 0 ou uma string vazia ""
. Portanto, a segunda parte (onde NF
é decrementada) só acontece se NF
não for 0.
A segunda parte (NF-=1
NF--
ou --NF
) está apenas subtraindo um da variável NF
. Isso evita que o último campo seja impresso, porque quando você altera um campo (removendo o último campo neste caso), awk
reconstrói $0
, concatena todos os campos separados por espaço por padrão . $0
não continha mais o último campo.
A parte final é 1
. Não é mágico, é apenas usado como uma expressão que significa true
. Se uma awk
expressão for avaliada como verdadeira sem qualquer ação associada, awk
a ação padrão é print $0
.
Comentários
- @JJoao: Ah, obrigado, esqueci
--
. Uma observação, atualmente, você precisa de;1
para compatibilidade com POSIX. - Meu instinto inicial seria usar um loop for, mas ele é muito mais conciso e inteligente.
- ' é importante notar que se você ' estiver usando um delimitador não padrão, você ' Terei de fazer algumas alterações. Supondo que
,
seja o seu delimitador:awk -F',' 'BEGIN { OFS = FS }; NF { NF -= 1 }; 1' < in > out
- O efeito de decrementar NF é um comportamento indefinido por POSIX – você obterá saída diferente dependendo de qual awk você ' está executando. Alguns awks removerão o último campo como você deseja, alguns não farão absolutamente nada e outros podem relatar um erro de sintaxe ou qualquer outra coisa.
Resposta
Usando grep
com PCRE:
$ grep -Po ".*(?=\s+[^\s]+$)" file.txt 1223 1234 1323 ... 2222 1233 1234 1233 ... 3444 0000 5553 3455 ... 2334
Usando GNU sed
:
$ sed -r "s/(.*)\s+[^\s]+$/\1/" file.txt 1223 1234 1323 ... 2222 1233 1234 1233 ... 3444 0000 5553 3455 ... 2334
Comentários
- @ramin Claro. . você poderia perguntar como uma nova pergunta (é assim que este site funciona) 🙂
- @ramin Fornece alguma restrição de tempo ou algum aviso?
- diz que isso está fora de questão!
- @ramin Ok … deixe-me entrar em contato com um administrador, pode ser que ele possa ajudá-lo com isso .. a propósito, você verificou algum controle de qualidade antigo em relação à sua pergunta? é uma possibilidade de que a pergunta já tenha sido feita e respondida.
- Não ' faça perguntas super básicas como " como posso renomear um nome de arquivo no Linux ". Use o Google.
Resposta
Usando Perl:
perl -lane "$,=" ";pop(@F);print(@F)" in
Usando rev
+ cut
:
rev in | cut -d " " -f 2- | rev
Resposta
Usando GNU sed:
sed -r "s/\s+\S+$//" input.txt
Mais geralmente, este funciona com BSD sed em OSX, bem como GNU sed:
sed "s/[[:space:]]\{1,\}[^[:space:]]\{1,\}$//" input.txt
Resposta
Se o delimitador for sempre um único caractere (então dois ou mais delimitadores consecutivos designam campos vazios), você poderia head
apenas a primeira linha do seu arquivo de entrada, contar os delimitadores ( n
delimitadores significa que o número de campos é n+1
) e use cut
para imprimir a partir do 1
st campo até o n
º campo (penúltimo), por exemplo com entrada delimitada por tabulação:
n=$(head -n 1 infile | tr -dc \\t | tr \\t \\n | wc -l) cut -f1-$n infile > outfile
ou por exemplocom um arquivo csv :
n=$(head -n 1 infile | tr -dc , | tr , \\n | wc -l) cut -d, -f1-$n infile > outfile
Vou rodar alguns benchmarks mais tarde se tiver tempo, mas com muita entrada, acho que isso solução deve ser mais rápida do que outras soluções que usam regex, já que esta faz o processamento mínimo na primeira linha para obter o número de campos e, em seguida, usa cut
, que é otimizado para este trabalho.
Resposta
Portavelmente, você pode usar qualquer um destes:
sed "s/[[:space:]]*[^[:space:]]*$//" file awk "{sub(/[[:space:]]*[^[:space:]]*$/,"")}1" file
Resposta
Usando o vim:
Abra o arquivo no vim
vim <filename>
Vá para a primeira linha, caso o cursor seja colocado em qualquer outro lugar.
gg
Crie uma macro chamada “q” qq
, que vai para o final da linha atual $
, depois volta para o último espaço F
(F maiúsculo, seguido de ESPAÇO literal) e exclua da posição atual até o final da linha D
vá para a próxima linha j
e pare a gravação da macro com q
.
qq$F Djq
Agora podemos repetir nossa macro com @q
para cada linha.
Também podemos pressionar @@
para repetir a última macro ou ainda mais fácil:
99@q
para repetir a macro 99 vezes.
Observação: O número não deve corresponder exatamente às linhas.
Resposta
Para pessoas que têm um problema semelhante, mas com separadores de campo diferentes, isso awk
preservará o separador de campo corretamente:
$ cat file foo.bar.baz baz.bar.foo $ awk -F"." "sub(FS $NF,x)" file foo.bar baz.bar
cut
soa como a ferramenta para o trabalho.