Hur man tar bort den sista kolumnen i en fil i Linux

Jag vill ta bort den sista kolumnen i en txt-fil, medan jag inte vet vad kolumnnumret är. Hur kunde jag göra det?

Exempel:

Ingång:

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

Och jag vill att min produktion ska vara :

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

Kommentarer

  • Det finns många sätt att göra detta … lägg till ett exempel och din förväntade effekt från den ..
  • @heemayl ok jag gjorde det
  • Tack..är kolumnerna fliken separerade eller mellanslag separerade?
  • @heemayl space is deliminator
  • cut låter som verktyget för jobbet.

Svar

Med awk:

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

eller:

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

eller:

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

Även om det här ser ut som voodoo fungerar det. Det finns tre delar till var och en av dessa awk-kommandon.

Den första är NF, vilket är en förutsättning för den andra delen. NF är en variabel som innehåller antalet fält i en rad. I AWK är saker sanna om de ”inte är 0 eller tomma strängar "". Därför minskas den andra delen (där NF minskas) händer bara om NF inte är 0.

Den andra delen (antingen NF-=1 NF-- eller --NF) subtraherar bara ett från variabeln NF. Detta förhindrar att det sista fältet skrivs ut, för när du ändrar ett fält (tar bort det sista fältet i det här fallet), awk omkonstruerar $0, sammanfogar alla fält åtskilda av mellanslag som standard . $0 innehöll inte det sista fältet längre.

Den sista delen är 1. Det är inte magiskt, det används bara som ett uttryck som betyder true. Om ett awk -uttryck utvärderas till sant utan någon associerad åtgärd är awk standardåtgärd print $0 .

Kommentarer

  • @JJoao: Ah, tack, glömde bort --. En anteckning, för närvarande, du behöver ;1 för POSIX-kompatibel.
  • Min första instinkt skulle vara att använda en for-loop, men det här är mycket mer kortfattat och smart.
  • Det är ' värt att notera att om du ' använder en icke-standardavgränsare, så ' Jag måste göra några ändringar. Förutsatt att , är din avgränsare: awk -F',' 'BEGIN { OFS = FS }; NF { NF -= 1 }; 1' < in > out
  • Effekten av att minska NF är odefinierat beteende av POSIX – du får olika utdata beroende på vilket awk du ' körs. Vissa awks tar bort det sista fältet som du vill, andra gör ingenting alls, och andra kan rapportera ett syntaxfel eller så annat.

Svar

Använd grep med PCRE:

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

Använda GNU sed:

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

Kommentarer

  • @ramin Visst. .Kan du ställa den som en ny fråga (så fungerar den här webbplatsen) 🙂
  • @ramin Ger det dig något tidsbegränsning eller någon varning?
  • det står att detta är uteslutet ifrågasatt!
  • @ramin Ok..låt mig kontakta en administratör, kanske de kan hjälpa dig med det .. btw kollade du någon gammal QA angående din fråga? det är en möjlighet att frågan redan är ställd och besvarad ..
  • Don ' t ställa super grundläggande frågor som " hur kan jag byta namn på ett filnamn i Linux ". Använd Google.

Svar

Med Perl:

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

Använda rev + cut:

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

Svar

Med GNU sed:

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

Mer allmänt, den här fungerar med BSD sed i OSX, liksom GNU sed:

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

Svar

Om avgränsaren alltid är en enda karaktär (så två eller flera på varandra följande avgränsare anger tomma fält) kan du head bara den första raden från din inmatningsfil, räkna avgränsarna ( n avgränsare betyder att antalet fält är n+1) använd sedan cut för att skriva ut från 1 st fält upp till n fältet (näst sista), t.ex. med tabbavgränsad ingång:

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

eller t.ex.med en csv fil:

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

Jag kommer att köra några riktmärken senare om jag har tid men med enorma insatser tror jag det här lösningen ska vara snabbare än andra lösningar som använder regex eftersom den här gör minimal bearbetning på första raden för att få antalet fält och använder sedan cut som är optimerad för det här jobbet.

Svar

Du kan använda något av dessa:

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

Svar

Använda vim:

Öppna fil i vim

vim <filename> 

Gå till första raden, bara om markören placeras någon annanstans.

gg 

Skapa ett makro med namnet ”q” qq, som går till baksidan av den aktuella raden $ och går sedan tillbaka till det sista mellanslaget F (huvudstad F, följt av bokstavligt mellanslag) ta sedan bort från aktuell position till slutet av raden D gå ner till nästa rad j och stoppa makroinspelning med q.

qq$F Djq 

Nu kan vi upprepa vårt makro med @q för varje rad.
Vi kan också trycka på @@ för att upprepa sista makrot eller ännu enklare:

99@q 

för att upprepa makrot 99 gånger.
Obs! Siffran får inte exakt matcha raderna.

Svar

För personer som har ett liknande problem men med olika fältseparatorer är detta awk -metoden kommer att bevara fältseparatorn korrekt:

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

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *