Hvordan slette den siste kolonnen i en fil i Linux

Jeg vil slette den siste kolonnen i en txt-fil, mens jeg ikke vet hva kolonnenummeret er. Hvordan kunne jeg gjøre dette?

Eksempel:

Inngang:

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

Og jeg vil at utdataene mine skal være :

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

Kommentarer

  • Det er mange måter å gjøre dette på. Vennligst legg til et eksempel og forventet resultat fra det ..
  • @heemayl ok jeg gjorde det
  • Takk..er kolonnefanen atskilt eller mellomrommet atskilt?
  • @heemayl space is deliminator
  • cut høres ut som verktøyet for jobben.

Svar

Med awk:

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

eller:

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

eller:

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

Selv om dette ser ut som voodoo, fungerer det. Det er tre deler til hver av disse awk-kommandoene.

Den første er NF, som er en forutsetning for den andre delen. NF er en variabel som inneholder antall felt i en linje. I AWK er ting sant hvis de «ikke er 0 eller tom streng "". Derfor blir den andre delen (der NF blir redusert) skjer bare hvis NF ikke er 0.

Den andre delen (enten NF-=1 NF-- eller --NF) trekker bare en fra NF -variabelen. Dette forhindrer at det siste feltet blir skrevet ut, for når du endrer et felt (fjerner det siste feltet i dette tilfellet), awk re-konstruerer $0, sammenføyer alle feltene atskilt med mellomrom som standard . $0 inneholdt ikke det siste feltet lenger.

Den siste delen er 1. Det er ikke magisk, det blir bare brukt som et uttrykk som betyr true. Hvis et awk -uttrykk evalueres til sant uten noen tilknyttet handling, er awk standardhandling print $0 .

Kommentarer

  • @JJoao: Ah, takk, glemte --. Et notat, for øyeblikket, trenger du ;1 for POSIX-kompatibel.
  • Mitt første instinkt ville være å bruke en for loop, men dette er mye mer konsist og smart.
  • Det er ' det er verdt å merke seg at hvis du ' bruker en ikke-standard skilletegn, vil du ' Jeg må gjøre noen endringer. Forutsatt at , er skillelinjen din: awk -F',' 'BEGIN { OFS = FS }; NF { NF -= 1 }; 1' < in > out
  • Effekten av å redusere NF er udefinert oppførsel av POSIX – du får forskjellig utgang, avhengig av hvilken uke du ' kjører. Noen awks vil fjerne det siste feltet som du vil, noen vil ikke gjøre noe i det hele tatt, og andre kan rapportere en syntaksfeil eller noe annet.

Svar

Bruk av grep med PCRE:

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

Bruk av GNU sed:

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

Kommentarer

  • @ramin Klart. .Kan du spørre det som et nytt spørsmål (slik fungerer dette nettstedet) 🙂
  • @ramin Gir det deg noe tidsbegrensning eller noen advarsler?
  • det står at dette er utenfor standard spørsmål!
  • @ramin Ok..La meg kontakte en administrator, kan det være de kan hjelpe deg med det .. btw sjekket du noen gamle QA angående spørsmålet ditt? det er en mulighet for at spørsmålet allerede er stilt og besvart ..
  • Don ' t stille super grunnleggende spørsmål som " hvordan kan jeg gi nytt navn til et filnavn i Linux ". Bruk Google.

Svar

Bruker Perl:

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

Bruke rev + cut:

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

Svar

Bruk av GNU sed:

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

Mer generelt, denne fungerer med BSD sed i OSX, samt GNU sed:

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

Svar

Hvis avgrenseren alltid er en enkelt tegn (så to eller flere påfølgende avgrensere angir tomme felt), kan du head bare den første linjen fra inndatafilen din, telle skillelinjene ( n skilletegn betyr at antall felt er n+1) bruk deretter cut for å skrive ut fra 1 st felt opp til n th feltet (nest siste), f.eks med tabulatoravgrenset inngang:

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

eller f.eks.med en csv fil:

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

Jeg kjører noen referanser senere hvis jeg har tid, men med store innspill tror jeg dette løsningen skal være raskere enn andre løsninger som bruker regex ettersom denne utfører minimal behandling på første linje for å få antall felt og bruker deretter cut som er optimalisert for denne jobben.

Svar

Portabelt kan du bruke en av disse:

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

Svar

Bruk av vim:

Åpne fil i vim

vim <filename> 

Gå til første rad, bare i tilfelle markøren plasseres noe annet sted.

gg 

Opprett en makro med navnet «q» qq, som går til baksiden av den nåværende linjen $, og går deretter tilbake til siste mellomrom F (hovedstad F, etterfulgt av bokstavelig SPACE), slett deretter fra nåværende posisjon til slutten av linjen D gå ned til neste linje j og stopp makroopptak med q.

qq$F Djq 

Nå kan vi gjenta makroen vår med @q for hver linje.
Vi kan også trykke @@ for å gjenta siste makro eller enda enklere:

99@q 

for å gjenta makroen 99 ganger.
Merk: Antallet må ikke stemme overens med linjene.

Svar

For folk som har et lignende problem, men med forskjellige feltskillere, er dette awk -metoden vil bevare feltutskilleren riktig:

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

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *