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
zara
fonte
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.

cuonglm
fonte
@ 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
heemail
fonte
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
kos
fonte
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
Trauma Digital
fonte
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.

don_crissti
fonte
1

Portably você pode usar um destes:

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

awk '{sub(/[[:space:]]*[^[:space:]]*$/,"")}1' file
Ed Morton
fonte
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.

cee
fonte
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
htaccess
fonte