Hoe de laatste kolom van een bestand in Linux te verwijderen

Ik wil de laatste kolom van een txt-bestand verwijderen, terwijl ik niet weet wat het kolomnummer is is. Hoe kan ik dit doen?

Voorbeeld:

Invoer:

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

En ik wil dat mijn uitvoer is :

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

Reacties

  • Er zijn veel manieren om dit te doen .. voeg alstublieft een voorbeeld toe en je verwachte output ervan ..
  • @heemayl ok ik deed het
  • Bedankt..zijn de kolommen tab gescheiden of spatie gescheiden?
  • @heemayl spatie is deliminator
  • cut klinkt als de tool voor de klus.

Antwoord

Met awk:

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

of:

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

of:

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

Hoewel dit op voodoo lijkt, werkt het. Elk van deze awk-opdrachten bestaat uit drie delen.

Het eerste is NF, wat een voorwaarde is voor het tweede deel. NF is een variabele die het aantal velden op een regel bevat. In AWK zijn dingen waar als ze “re niet 0 of lege string "" zijn. Vandaar dat het tweede deel (waarbij NF wordt verlaagd) gebeurt alleen als NF niet 0 is.

Het tweede deel (ofwel NF-=1 NF-- of --NF) trekt er gewoon een af van de NF variabele. Dit voorkomt dat het laatste veld wordt afgedrukt, want wanneer je wijzigt een veld (verwijdert in dit geval het laatste veld), awk herbouw $0, voeg standaard alle velden samen die door een spatie zijn gescheiden . $0 bevatte het laatste veld niet meer.

Het laatste deel is 1. Het is niet magisch, het wordt alleen gebruikt als een uitdrukking die true betekent. Als een awk uitdrukking naar true evalueert zonder enige bijbehorende actie, is awk standaardactie print $0 .

Reacties

  • @JJoao: Ah, bedankt, ben -- vergeten. Een opmerking, momenteel heb je ;1 nodig voor POSIX-compliant.
  • Mijn aanvankelijke instinct zou zijn om een for-lus te gebruiken, maar dit is veel beknopter en slimmer.
  • Het ' is het vermelden waard dat als u ' een niet-standaard scheidingsteken gebruikt, u ' Ik zal enkele wijzigingen moeten aanbrengen. Ervan uitgaande dat , uw scheidingsteken is: awk -F',' 'BEGIN { OFS = FS }; NF { NF -= 1 }; 1' < in > out
  • Het effect van het verlagen van NF is ongedefinieerd gedrag door POSIX – u krijgt verschillende uitvoer afhankelijk van welke awk u ' opnieuw draait. Sommige awks zullen het laatste veld verwijderen zoals je wilt, sommige doen helemaal niets, en anderen kunnen een syntaxisfout rapporteren of iets anders.

Antwoord

grep gebruiken met PCRE:

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

GNU gebruiken sed:

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

Reacties

  • @ramin Zeker. . Kunt u het alstublieft stellen als een nieuwe vraag (zo werkt deze site) 🙂
  • @ramin Geeft het u enige tijdsbeperking of enige waarschuwing?
  • er staat dat dit geen standaardvraag is!
  • @ramin Ok..laat me contact opnemen met een beheerder, misschien kunnen zij je ermee helpen .. btw heb je een oude QA gecontroleerd met betrekking tot je vraag? het is een mogelijkheid dat de vraag al is gesteld en beantwoord.
  • Don ' stel geen super eenvoudige vragen zoals " hoe kan ik een bestandsnaam hernoemen in Linux ". Gebruik Google.

Answer

Perl gebruiken:

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

Met rev + cut:

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

Answer

GNU gebruiken sed:

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

Meer in het algemeen, deze werkt met de BSD sed in OSX, evenals GNU sed:

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

Answer

Als het scheidingsteken altijd een enkel teken is (dus twee of meer opeenvolgende scheidingstekens duiden lege velden aan), kunt u head alleen de eerste regel uit uw invoerbestand tellen, de scheidingstekens tellen ( n scheidingstekens betekent dat het aantal velden n+1 is) en gebruik vervolgens cut om af te drukken vanaf de 1 st veld tot aan het n veld (voorlaatste), bijv. met door tabs gescheiden invoer:

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

of bijv.met een csv -bestand:

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

Ik zal later wat benchmarks uitvoeren als ik de tijd heb, maar met enorme input denk ik dit oplossing zou sneller moeten zijn dan andere oplossingen die regex gebruiken, aangezien deze minimale verwerking op de eerste regel uitvoert om het aantal velden te krijgen en vervolgens cut gebruikt dat is geoptimaliseerd voor deze taak.

Antwoord

Draagbaar kunt u een van deze gebruiken:

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

Antwoord

Met vim:

Open bestand in vim

vim <filename> 

Ga naar de eerste rij, voor het geval de cursor ergens anders staat.

gg 

Maak een macro met de naam “q” qq, dat naar de achterkant van de huidige regel gaat $, en dan teruggaat naar de laatste spatie F (hoofdletter F, gevolgd door letterlijke SPATIE) en vervolgens verwijderen vanaf de huidige positie tot het einde van de regel D ga naar de volgende regel j en stop de macro-opname met q.

qq$F Djq 

Nu kunnen we onze macro herhalen met @q voor elke regel.
We kunnen ook op @@ om de laatste macro te herhalen of nog gemakkelijker:

99@q 

om de macro 99 keer te herhalen.
Opmerking: het nummer mag niet exact overeenkomen met de regels.

Antwoord

Voor mensen met een soortgelijk probleem maar met verschillende veldscheidingstekens is dit awk methode zal het veldscheidingsteken correct bewaren:

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

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *