Come eliminare lultima colonna di un file in Linux

Voglio eliminare lultima colonna di un file txt, mentre non so quale sia il numero di colonna è. Come potrei farlo?

Esempio:

Input:

1223 1234 1323 ... 2222 123 1233 1234 1233 ... 3444 125 0000 5553 3455 ... 2334 222 

E voglio che il mio output sia :

1223 1234 1323 ... 2222 1233 1234 1233 ... 3444 0000 5553 3455 ... 2334 

Commenti

  • Ci sono molti modi per farlo .. aggiungi un esempio e il tuo output atteso da esso ..
  • @heemayl ok lho fatto
  • Grazie .. le colonne sono separate da tabulazioni o da spazi?
  • @heemayl lo spazio è delimitatore
  • cut suona come lo strumento per il lavoro.

Risposta

Con awk:

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

o:

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

oppure:

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

Anche se sembra voodoo, funziona. Ci sono tre parti in ciascuno di questi comandi awk.

La prima è NF, che è una precondizione per la seconda parte. NF è una variabile contenente il numero di campi in una riga. In AWK, le cose sono vere se “non sono 0 o una stringa vuota "". Quindi, la seconda parte (dove NF è decrementata) accade solo se NF non è 0.

La seconda parte (o NF-=1 NF-- o --NF) sta solo sottraendo uno dalla variabile NF. Ciò impedisce la stampa dellultimo campo, perché quando si modifica un campo (rimuovendo lultimo campo in questo caso), awk ricostruisce $0, concatena tutti i campi separati da spazio per impostazione predefinita . $0 non conteneva più lultimo campo.

La parte finale è 1. Non è “magico”, è solo usato come espressione che significa true. Se unespressione awk restituisce true senza alcuna azione associata, awk azione predefinita è print $0 .

Commenti

  • @JJoao: Ah, grazie, mi sono dimenticato di --. Una nota, attualmente, è necessario ;1 per essere compatibile con POSIX.
  • Il mio istinto iniziale sarebbe quello di utilizzare un ciclo for, ma questo è molto più conciso e intelligente.
  • È ' degno di nota che se ' stai utilizzando un delimitatore non predefinito, ' sarà necessario apportare alcune modifiche. Supponendo che , sia il tuo delimitatore: awk -F',' 'BEGIN { OFS = FS }; NF { NF -= 1 }; 1' < in > out
  • Leffetto del decremento di NF è un comportamento indefinito di POSIX – otterrai output diverso a seconda di quale awk ' stai utilizzando. Alcuni awk rimuoveranno lultimo campo come desideri, altri non faranno nulla e altri potrebbero segnalare un errore di sintassi o altro.

Risposta

Utilizzo di grep con PCRE:

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

Utilizzo di GNU sed:

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

Commenti

  • @ramin Sure. .Potresti chiederla come una nuova domanda (è così che funziona questo sito) 🙂
  • @ramin Ti dà qualcosa limiti di tempo o avvisi?
  • dice che è fuori questione standard!
  • @ramin Ok .. lasciami contattare un amministratore, potrebbe essere che ti possa aiutare .. btw hai controllato qualche vecchio QA riguardo alla tua domanda? è possibile che la domanda sia già stata posta e abbia già risposto ..
  • Non ' t fare domande di base come " come posso rinominare un nome file in Linux ". Utilizza Google.

Rispondi

Utilizzo di Perl:

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

Utilizzo di rev + cut:

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

Risposta

Utilizzo di GNU sed:

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

Più in generale, questo funziona con BSD sed in OSX, così come GNU sed:

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

Answer

Se il delimitatore è sempre un singolo carattere (quindi due o più delimitatori consecutivi designano campi vuoti), potresti head solo la prima riga del tuo file di input, contare i delimitatori ( n delimitatori significa che il numero di campi è n+1), quindi utilizza cut per stampare dal 1 st campo fino al n esimo campo (dal penultimo), ad es. con input delimitato da tabulazioni:

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

o ad es.con un file csv :

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

eseguirò alcuni benchmark più tardi se avrò tempo ma con un input enorme penso che questo la soluzione dovrebbe essere più veloce di altre soluzioni che utilizzano regex poiché questa esegue unelaborazione minima sulla prima riga per ottenere il numero di campi e quindi utilizza cut, ottimizzato per questo lavoro.

Risposta

Portabilmente puoi utilizzare uno di questi:

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

Risposta

Utilizzo di vim:

Apri file in vim

vim <filename> 

Vai alla prima riga, nel caso in cui il cursore sia posizionato altrove.

gg 

Crea una macro denominata “q” qq, che va in fondo alla riga corrente $, quindi torna allultimo spazio F (F maiuscola, seguita da SPAZIO letterale) quindi elimina dalla posizione corrente fino alla fine della riga D vai alla riga successiva j e interrompi la registrazione della macro con q.

qq$F Djq 

Ora possiamo ripetere la nostra macro con @q per ogni riga.
Possiamo anche premere @@ per ripetere lultima macro o anche più facilmente:

99@q 

per ripetere la macro 99 volte.
Nota: il numero non deve corrispondere esattamente alle righe.

Risposta

Per le persone che hanno un problema simile ma con separatori di campo diversi, questo awk conserverà correttamente il separatore di campo:

$ cat file foo.bar.baz baz.bar.foo $ awk -F"." "sub(FS $NF,x)" file foo.bar baz.bar 

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *