Como excluir a última coluna de um arquivo no Linux


25

Desejo excluir a última coluna de um arquivo txt, enquanto não sei qual é o número da coluna. Como eu pude 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

Há muitas maneiras de fazer this..please adicionar um exemplo e sua saída esperada a partir dele ..
heemayl

@heemayl ok eu fiz
zara

Obrigado ... a guia de colunas é separada ou o espaço é separado?
Hemayl # 7/15

@heemayl space is deliminator
zara

Respostas:


43

Com awk:

awk 'NF{NF-=1};1' <in >out

ou:

awk 'NF{NF--};1' <in >out

ou:

awk 'NF{--NF};1' <in >out

Embora isso pareça vodu, ele funciona. Existem três partes para cada um desses comandos do awk.

O primeiro é 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 string vazia "". Portanto, a segunda parte (onde NFé decrementada) só acontece se NFnão for 0.

A segunda parte ( NF-=1 NF--ou --NF) está apenas subtraindo uma da NFvariável. Isso impede que o último campo seja impresso, porque quando você altera um campo (removendo o último campo neste caso), awkrecria $0, concatena todos os campos separados por espaço por padrão. $0nã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 awkexpressão for avaliada como verdadeira sem nenhuma ação associada, a awkação padrão será print $0.


@ João: Ah, obrigado, esqueci --. Uma observação, atualmente, você precisa estar ;1em conformidade com o POSIX.
precisa saber é

Meu instinto inicial seria usar um loop for, mas isso é muito mais conciso e inteligente.
Sergiy Kolodyazhnyy

5
Vale ressaltar que, se você estiver usando um delimitador não padrão, precisará fazer algumas alterações. Assumindo que ,é o seu delimitador:awk -F',' 'BEGIN { OFS = FS }; NF { NF -= 1 }; 1' < in > out
Sr. Llama

11
O efeito de decrementar a NF é um comportamento indefinido do POSIX - você terá uma saída diferente dependendo do awk que está executando. Alguns awks removerão o último campo como você deseja, outros não farão nada e outros poderão relatar um erro de sintaxe ou qualquer outra coisa.
Ed Morton

16

Usando grepcom PCRE:

$ grep -Po '.*(?=\s+[^\s]+$)' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334

Usando o GNU sed:

$ sed -r 's/(.*)\s+[^\s]+$/\1/' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334

11
@ramin Sure..could você por favor, pergunte-lo como uma nova pergunta (isto é como esse site funciona) :)
heemayl

@ramin Isso lhe dá alguma restrição de tempo ou aviso?
Hemayl # 7/15

diz que isso está fora de questão!
zara

@ramin Ok .. deixe-me entrar em contato com um administrador, pode ser que eles possam ajudá-lo .. mas você verificou algum controle de qualidade antigo referente à sua pergunta? é uma possibilidade de que a questão já está feita e respondida ..
heemayl

3
Não faça perguntas super básicas como " como posso renomear um nome de arquivo no Linux ". Use Google.
Christoffer Hammarström

11

Usando Perl:

perl -lane '$,=" ";pop(@F);print(@F)' in

Usando rev+ cut:

rev in | cut -d ' ' -f 2- | rev

5

Usando o GNU sed:

sed -r 's/\s+\S+$//' input.txt

De um modo mais geral, este funciona com o BSD sed no OSX, assim como o GNU sed:

sed 's/[[:space:]]\{1,\}[^[:space:]]\{1,\}$//' input.txt

1

Se o delimitador é sempre um único caractere (para que dois ou mais delimitadores consecutivos designem campos vazios), você pode headapenas a primeira linha do seu arquivo de entrada, contar os delimitadores ( ndelimitadores significa que o número de campos é n+1) e usá-lo cutpara imprimir no 1campo st até o nquinto campo (do penúltimo ao ú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 exemplo, com um arquivo csv :

n=$(head -n 1 infile | tr -dc , | tr , \\n | wc -l)
cut -d, -f1-$n infile > outfile

Vou executar alguns benchmarks mais tarde, se tiver tempo, mas com uma grande quantidade de informações, acho que essa solução deve ser mais rápida do que outras soluções que usam regex, pois essa processa o mínimo na primeira linha para obter o não. de campos e, em seguida, usa o cutque é otimizado para este trabalho.


1

Portably você pode usar um destes:

sed 's/[[:space:]]*[^[:space:]]*$//' file

awk '{sub(/[[:space:]]*[^[:space:]]*$/,"")}1' file

0

Usando o vim:

Abrir arquivo no vim

vim <filename> 

Vá para a primeira linha, caso o cursor seja colocado em qualquer outro lugar.

gg

Crie uma macro denominada "q" qq, que vá para o final da linha atual $, depois para o último espaço F(capital F, seguido de literal ESPAÇO) e exclua da posição atual até o final da linha, Ddesça para a próxima linha je pare a gravação de macro com q.

qq$F Djq

Agora podemos repetir nossa macro com @qpara cada linha.
Também podemos pressionar @@para repetir a última macro ou ainda mais fácil:

99@q

repetir a macro 99 vezes.
Nota: O número não deve corresponder exatamente às linhas.


0

Para pessoas que têm um problema semelhante, mas com separadores de campos diferentes, esse awkmétodo preservará o separador de campos corretamente:

$ cat file 
foo.bar.baz
baz.bar.foo
$ awk -F'.' 'sub(FS $NF,x)' file
foo.bar
baz.bar
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.