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
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
cut
suona come lo strumento per il lavoro.