Vreau să șterg ultima coloană a unui fișier txt, în timp ce nu știu care este numărul coloanei este. Cum aș putea face acest lucru?
Exemplu:
Intrare:
1223 1234 1323 ... 2222 123 1233 1234 1233 ... 3444 125 0000 5553 3455 ... 2334 222
Și vreau ca ieșirea mea să fie :
1223 1234 1323 ... 2222 1233 1234 1233 ... 3444 0000 5553 3455 ... 2334
Comentarii
Răspuns
Cu awk
:
awk "NF{NF-=1};1" <in >out
sau:
awk "NF{NF--};1" <in >out
sau:
awk "NF{--NF};1" <in >out
Deși acest lucru arată ca voodoo, funcționează. Există trei părți pentru fiecare dintre aceste comenzi awk.
Prima este NF
, care este o condiție prealabilă pentru a doua parte. NF
este o variabilă care conține numărul de câmpuri dintr-o linie. În AWK, lucrurile sunt adevărate dacă „nu sunt 0 sau șirul gol ""
. Prin urmare, a doua parte (unde NF
este decrementată) se întâmplă numai dacă NF
nu este 0.
A doua parte (fie NF-=1
NF--
sau --NF
) scade doar una din variabila NF
. Aceasta împiedică tipărirea ultimului câmp, deoarece atunci când schimbi un câmp (eliminând ultimul câmp în acest caz), awk
reconstruiește $0
, concatenează toate câmpurile separate de spațiu în mod implicit . $0
nu mai conținea ultimul câmp.
Partea finală este 1
. „Nu este magic, este doar folosit ca o expresie care înseamnă true
. Dacă o expresie awk
se evaluează la adevărat fără nicio acțiune asociată, awk
acțiune implicită este print $0
.
Comentarii
- @JJoao: Ah, mulțumesc, am uitat de
--
. O notă, în prezent, aveți nevoie de;1
pentru compatibilitatea POSIX. - Instinctul meu inițial ar fi să folosesc o buclă for, dar aceasta este mult mai concisă și mai inteligentă.
- Merită menționat ' că, dacă ' utilizați un delimitator non-implicit, ' va trebui să facă unele modificări. Presupunând că
,
este delimitatorul dvs.:awk -F',' 'BEGIN { OFS = FS }; NF { NF -= 1 }; 1' < in > out
- Efectul decrementării NF este un comportament nedefinit de POSIX – veți obține ieșire diferită în funcție de starea pe care o executați '. Unele awks vor elimina ultimul câmp după cum doriți, altele nu vor face deloc, iar altele ar putea raporta o eroare de sintaxă sau orice altceva.
Răspuns
Utilizarea grep
cu PCRE:
$ grep -Po ".*(?=\s+[^\s]+$)" file.txt 1223 1234 1323 ... 2222 1233 1234 1233 ... 3444 0000 5553 3455 ... 2334
Utilizarea GNU sed
:
$ sed -r "s/(.*)\s+[^\s]+$/\1/" file.txt 1223 1234 1323 ... 2222 1233 1234 1233 ... 3444 0000 5553 3455 ... 2334
Comentarii
- @ramin Sigur. .ar puteai să o întrebați ca o nouă întrebare (așa funcționează acest site) 🙂
- @ramin Vă oferă ceva restricție de timp sau vreun avertisment?
- se spune că nu este o întrebare standard!
- @ramin Ok .. permiteți-mi să contactez un administrator, poate că te pot ajuta cu asta .. ați verificat vreun QA vechi cu privire la întrebarea dvs.? este o posibilitate ca întrebarea să fie deja pusă și răspunsă.
- Nu ' nu puneți întrebări super de bază precum " cum pot redenumi un nume de fișier în Linux ". Utilizați Google.
Răspuns
Utilizarea Perl:
perl -lane "$,=" ";pop(@F);print(@F)" in
Utilizarea rev
+ cut
:
rev in | cut -d " " -f 2- | rev
Răspuns
Utilizarea sed GNU:
sed -r "s/\s+\S+$//" input.txt
Mai general, acesta funcționează cu BSD sed în OSX, precum și cu GNU sed:
sed "s/[[:space:]]\{1,\}[^[:space:]]\{1,\}$//" input.txt
Răspuns
Dacă delimitatorul este întotdeauna un singur caracter (deci doi sau mai mulți delimitatori consecutivi desemnează câmpuri goale), puteți head
doar prima linie din fișierul de intrare, numărați delimitatorii ( n
delimitatori înseamnă că numărul de câmpuri este n+1
), apoi utilizați cut
pentru a imprima din 1
st câmp până la n
th câmp (de la al doilea la ultimul), de ex. cu intrare delimitată de tab-uri:
n=$(head -n 1 infile | tr -dc \\t | tr \\t \\n | wc -l) cut -f1-$n infile > outfile
sau de ex.cu un fișier csv :
n=$(head -n 1 infile | tr -dc , | tr , \\n | wc -l) cut -d, -f1-$n infile > outfile
Voi rula câteva repere mai târziu dacă am timp, dar cu o intrare imensă cred că acest lucru soluția ar trebui să fie mai rapidă decât alte soluții care utilizează regex, deoarece aceasta face o procesare minimă pe prima linie pentru a obține numărul câmpurilor și apoi folosește cut
, care este optimizat pentru acest job. / p>
Răspuns
Portabil, puteți utiliza oricare dintre acestea:
sed "s/[[:space:]]*[^[:space:]]*$//" file awk "{sub(/[[:space:]]*[^[:space:]]*$/,"")}1" file
Răspuns
Folosind vim:
Deschideți fișierul în vim
vim <filename>
Mergeți la primul rând, doar în cazul în care cursorul este plasat în altă parte.
gg
Creați o macro numită „q” qq
, care merge în spatele liniei curente $
, apoi revine la ultimul spațiu F
(F majusculă, urmată de spațiu literal) apoi ștergeți din poziția curentă până la sfârșitul liniei D
mergeți la linia următoare j
și opriți înregistrarea macro cu q
.
qq$F Djq
Acum putem repeta macro-ul nostru cu @q
pentru fiecare linie.
Putem apăsa și @@
pentru a repeta ultima macrocomandă sau chiar mai ușor:
99@q
pentru a repeta macrocomanda de 99 de ori.
Notă: numărul nu trebuie să se potrivească exact cu liniile.
Răspuns
Pentru persoanele care au o problemă similară, dar cu separatori de câmp diferiți, acest awk
va păstra corect separatorul de câmp:
$ cat file foo.bar.baz baz.bar.foo $ awk -F"." "sub(FS $NF,x)" file foo.bar baz.bar
cut
sună ca instrumentul pentru job.