Hoe gebruik je een shell-commando om alleen de eerste kolom en de laatste kolom in een tekstbestand weer te geven?

Ik heb wat hulp nodig om erachter te komen hoe ik het sed commando kan gebruiken om alleen de eerste kolom en de laatste kolom in een tekstbestand te tonen. Dit is wat ik tot nu toe heb voor kolom 1:

cat logfile | sed "s/\|/ /"|awk "{print $1}" 

Mijn zwakke poging om ook de laatste kolom weer te geven was:

cat logfile | sed "s/\|/ /"|awk "{print $1}{print $8}" 

Dit neemt echter de eerste kolom en de laatste kolom en voegt ze samen in één lijst. Is er een manier om de eerste kolom en laatste kolommen duidelijk af te drukken met sed- en awk-opdrachten?

Voorbeeldinvoer:

foo|dog|cat|mouse|lion|ox|tiger|bar 

Opmerkingen

  • Geef wat voorbeeldinvoer.

Antwoord

Bijna klaar. Plaats beide kolomverwijzingen gewoon naast elkaar.

cat logfile | sed "s/|/ /" | awk "{print $1, $8}" 

Merk ook op dat u cat hier niet nodig hebt .

sed "s/|/ /" logfile | awk "{print $1, $8}" 

Merk ook op dat u awk kunt vertellen dat de kolomscheidingstekens |, in plaats van spaties, dus je hebt sed ook niet nodig.

awk -F "|" "{print $1, $8}" logfile 

Volgens suggesties door Caleb , als u een oplossing wilt die nog steeds het laatste veld uitvoert , zelfs als het er niet precies acht zijn, kunt u $NF gebruiken.

awk -F "|" "{print $1, $NF}" logfile 

Ook als u de uitvoer om de scheidingstekens | te behouden, in plaats van een spatie te gebruiken, kunt u de scheidingstekens voor het uitvoerveld specificeren. Helaas is het een beetje onhandiger dan alleen het gebruik van de -F vlag, maar hier zijn drie benaderingen.

  • U kunt de invoer toewijzen en uitvoerveldscheidingstekens in awk zelf, in het BEGIN-blok.

    awk "BEGIN {FS = OFS = "|"} {print $1, $8}" logfile 
  • U kunt deze variabelen toewijzen wanneer u awk aanroept vanaf de opdrachtregel, via de vlag -v.

    awk -v "FS=|" -v "OFS=|" "{print $1, $8}" logfile 
  • of simpelweg:

    awk -F "|" "{print $1 "|" $8}" logfile 

Opmerkingen

  • Goed werk om te beschrijven hoe dit probleem kan worden vereenvoudigd. U kunt een opmerking toevoegen over hoe u | als uitvoerscheidingsteken kunt gebruiken in plaats van de standaardruimte voor het samenvoegen van tekenreeksen. Je zou ook kunnen uitleggen om $NF te gebruiken in plaats van hard te coderen $8 om de laatste kolom te krijgen.
  • hoe het bestand daarna te updaten?
  • @pankajprasad Schrijf naar een nieuw bestand met h > en overschrijf dan de oude, of gebruik sponge. Dit is echter echt een nieuwe vraag.
  • @Sparhawk het werkt, maar de inhoud wordt gewist. hoe daarmee om te gaan?
  • @pankajprasad Je moet een nieuwe vraag stellen. Klik op de grote blauwe knop bovenaan met de tekst ” Vraag stellen “.

Answer

Je gebruikt toch awk:

awk "{ print $1, $NF }" file 

Reacties

  • Zou je niet ‘ moeten opgeven als het scheidingsteken voor het invoerveld moet worden opgegeven (aangezien het in dit geval | in plaats van die spatie) zijn met -F\| of iets dergelijks? En wat als hij hetzelfde scheidingsteken wilde gebruiken voor uitvoer?
  • @Caleb Waarschijnlijk: ik wachtte op het OP om te bevestigen hoe precies de invoer eruitzag, in plaats van te proberen gok gebaseerd op de niet-werkende voorbeelden …
  • Merk op dat dit veronderstelt dat de invoer minstens 2 velden bevat.
  • @St é phaneChazelas OP vermeldde duidelijk in de code dat het altijd acht velden heeft.
  • @ michaelb958 Ik denk dat ” duidelijk ” overdrijft de zaak, alleen een beetje 🙂

Antwoord

Vervang gewoon van de eerste naar de laatste | met een | (of spatie als je dat liever hebt):

sed "s/|.*|/|/" 

Merk op dat hoewel er “geen sed implementatie is waar | speciaal is (zolang uitgebreid regulier expressies zijn niet ingeschakeld via -E of in sommige implementaties), \| zelf is speciaal in sommige zoals GNU sed. Dus je moet niet ontsnappen aan | als je van plan bent dat het overeenkomt met het | karakter.

Als u het vervangt door spatie en als de invoer al regels bevat met slechts één |, dan “moet u dat speciaal behandelen als |.*| zal daar niet op matchen.Dat zou kunnen zijn:

sed "s/|\(.*|\)\{0,1\}/ /" 

(dat wil zeggen: maak het .*| deel optioneel) Of:

sed "s/|.*|/ /;s/|/ /" 

of:

sed "s/\([^|]*\).*|/\1 /" 

Als u de eerste en achtste velden wilt, ongeacht het aantal velden in de invoer, dan is het gewoon:

cut -d"|" -f1,8 

(al deze zouden werken met elk POSIX-compatibel hulpprogramma, ervan uitgaande dat de invoer vormt geldige tekst (in het bijzonder de sed degenen zullen over het algemeen niet werken als de invoer bytes of reeksen bytes bevat die geen geldige tekens vormen in de huidige landinstelling, zoals bijvoorbeeld printf "unix|St\351phane|Chazelas\n" | sed "s/|.*|/|/" in een UTF-8-landinstelling)).

Answer

Als je merkt dat je onhandig en sed-less bent, kun je de hetzelfde met coreutils:

paste <( cut -d"|" -f1 file) \ <(rev file | cut -d"|" -f1 | rev) 

Reacties

  • cut is schoner en compacter dan awk / sed als je alleen geïnteresseerd bent in de eerste kolom, of als de begrenzingen vast zijn (dwz niet een variabel aantal spaties).
  • Behoorlijk elegant!

Antwoord

Het lijkt erop dat u probeert de eerste en laatste tekstvelden te krijgen die worden gescheiden door |.

Ik ging ervan uit dat uw logbestand de onderstaande tekst bevat,

foo|dog|cat|mouse|lion|ox|tiger|bar bar|dog|cat|mouse|lion|ox|tiger|foo 

En u wilt de output zoals,

foo bar bar foo 

Zo ja, dan komt hier het commando voor jouw “s

Via GNU sed,

sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" file 

Voorbeeld:

$ echo "foo|dog|cat|mouse|lion|ox|tiger|bar" | sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" foo bar 

Reacties

  • De kolommen worden niet gescheiden door een pijp | maar ze staan in kolommen, ik ben geïnteresseerd in het gebruik van sed maar niet in het gebruik van het awk-commando zoals je deed in je commando: sed -r ‘ s ~ ^ ([^ |] *) . * \ | (. *) $ ~ \ 1 \ 2 ~ ‘ bestand
  • ” De kolommen zijn niet afgebakend door een pijp | maar ze staan in kolommen “, bedoel je dat kolommen worden gescheiden door spaties?
  • Een voorbeeldinvoer en een uitvoer zouden beter zijn.

Antwoord

Je zou het waarschijnlijk moeten doen met sed – ik zou het toch doen – maar, want nog niemand heeft deze geschreven:

while IFS=\| read col1 cols do printf %10s%-s\\n "$col1 |" " ${cols##*|}" done <<\INPUT foo|dog|cat|mouse|lion|ox|tiger|bar INPUT 

OUTPUT

 foo | bar 

Geef een reactie

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