Hur använder jag ett skalkommando för att bara visa den första kolumnen och den sista kolumnen i en textfil?

Jag behöver lite hjälp för att ta reda på hur man använder kommandot sed för att endast visa den första kolumnen och den sista kolumnen i en textfil. Här är vad jag hittills har för kolumn 1:

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

Mitt svaga försök att få den sista kolumnen att visas också var:

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

Detta tar dock den första kolumnen och den sista kolumnen och slår samman dem i en lista. Finns det ett sätt att skriva ut den första och den sista kolumnen tydligt med sed- och awk-kommandon?

Exempelinmatning:

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

Kommentarer

  • Ange en del exempelinmatning.

Svar

Nästan där. Lägg bara båda kolumnreferenser bredvid varandra.

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

Observera också att du inte behöver cat här .

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

Observera också att du kan säga awk att kolumnavgränsarna är | istället för tomma, så behöver du inte heller sed.

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

Enligt förslag av Caleb , om du vill ha en lösning som fortfarande matar ut det sista fältet , även om det inte finns exakt åtta, kan du använda $NF.

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

Om du vill ha utdata för att behålla separatorerna |, istället för att använda ett mellanslag kan du ange utmatningsfältavgränsarna. Tyvärr är det lite klumpigare än att bara använda flaggan -F, men här är tre metoder.

  • Du kan tilldela ingången och utmatningsfältavskiljare i awk i BEGIN-blocket.

    awk "BEGIN {FS = OFS = "|"} {print $1, $8}" logfile 
  • Du kan tilldela dessa variabler när du ringer till awk från kommandoraden via flaggan -v.

    awk -v "FS=|" -v "OFS=|" "{print $1, $8}" logfile 
  • eller helt enkelt:

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

Kommentarer

  • Bra jobb med att bryta ner hur detta problem kan förenklas. Du kan lägga till en anteckning om hur du använder | som en utmatningsavgränsare istället för standardutrymmet för strängsammankoppling. Du kan också förklara att du använder $NF istället för hårdkodning $8 för att få den sista kolumnen.
  • efter det hur man uppdaterar filen?
  • @pankajprasad Skriv till en ny fil med h > skriv sedan över den gamla, eller använd sponge. Det här är verkligen en ny fråga.
  • @Sparhawk det fungerar, men innehållet raderas raderas. hur ska man hantera det?
  • @pankajprasad Du måste ställa en ny fråga. Klicka på den stora blå knappen uppåt som säger ” Ställ fråga ”.

Svar

Du använder awk ändå:

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

Kommentarer

  • Skulle ’ t du behöver ange inmatningsfältavgränsaren (eftersom det i det här fallet verkar vara | snarare det utrymmet) med -F\| eller liknande? Tänk också om han ville använda samma avgränsare för utdata?
  • @Caleb Förmodligen: Jag väntade på att OP skulle bekräfta hur exakt ingången såg ut, snarare än att försöka gissa baserat på de icke-fungerande exemplen …
  • Observera att det antas att ingången innehåller minst två fält.
  • @St é phaneChazelas OP angav tydligt i koden att det alltid har åtta fält.
  • @ michaelb958 Jag tror att ” tydligt ” överdriver fallet, bara lite 🙂

Svar

Byt bara från första till sista | med en | (eller mellanslag om du föredrar):

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

Observera att även om det inte finns någon sed implementering där | är speciell (så länge som utökad regelbunden uttryck är inte aktiverade via -E eller i vissa implementeringar), \| i sig är speciellt i vissa som GNU sed. Så du bör inte fly | om du tänker att den ska matcha | karaktär.

Om du ersätter med mellanslag och om ingången redan kan innehålla rader med endast en |, måste du behandla det speciellt som |.*| vann inte match på dessa.Det kan vara:

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

(det vill säga att .*| -delen är valfri) Eller:

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

eller:

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

Om du vill ha första och åttonde fälten oavsett antalet fält i ingången, då är det bara:

cut -d"|" -f1,8 

(alla de skulle fungera med alla POSIX-kompatibla verktyg förutsatt att ingången bildar giltig text (i synnerhet sed kommer vanligtvis inte att fungera om ingången har byte eller sekvenser av byte som inte bildar giltiga tecken i den aktuella platsen som t.ex. printf "unix|St\351phane|Chazelas\n" | sed "s/|.*|/|/" i ett UTF-8-språk)).

Svar

Om du tycker att du är obekväm och lugnare kan du uppnå samma sak med coreutils:

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

Kommentarer

  • cut är renare och mer kompakt än awk / sed när du bara är intresserad av den första kolumnen, eller om avgränsningarna är fasta (dvs inte ett varierande antal mellanslag).
  • Ganska elegant!

Svar

Det verkar som om du försöker få det första och sista textfältet som avgränsas av |.

Jag antar att din loggfil innehåller texten som nedan,

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

Och du vill utdata som,

foo bar bar foo 

Om ja, då kommer kommandot för dina ”s

Genom GNU sed,

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

Exempel:

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

Kommentarer

  • Kolumnerna avgränsas inte av ett rör | men de finns i kolumner, jag är intresserad av att använda sed men inte använda kommandot awk som du gjorde i ditt kommando: sed -r ’ s ~ ^ ([^ |] *) . * \ | (. *) $ ~ \ 1 \ 2 ~ ’ fil
  • ” Kolumnerna är avgränsas inte av ett rör | men de finns i kolumner ”, menar du att kolumner är åtskilda av mellanslag?
  • En provingång och en utdata skulle vara bättre.

Svar

Du borde nog göra det med sed – jag skulle ändå göra det – men bara för att ingen har skrivit den här ännu:

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

UTGÅNG

 foo | bar 

Lämna ett svar

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