Jak pomocí příkazu prostředí zobrazit pouze první sloupec a poslední sloupec v textovém souboru?

Potřebuji pomoc, abych zjistil, jak pomocí příkazu sed zobrazit pouze první sloupec a poslední sloupec v textovém souboru. Tady je to, co zatím pro sloupec 1:

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

Můj slabý pokus o zobrazení posledního sloupce byl také:

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

Toto však vezme první a poslední sloupec a sloučí je do jednoho seznamu. Existuje způsob, jak jasně vytisknout první sloupec a poslední sloupce pomocí příkazů sed a awk?

Ukázkový vstup:

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

Komentáře

  • Uveďte prosím ukázkový vstup.

Odpověď

Téměř tam. Stačí dát oba odkazy na sloupce vedle sebe.

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

Upozorňujeme, že zde cat nepotřebujete .

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

Upozorňujeme, že awk je oddělovač sloupců | místo mezer, takže nepotřebujete sed.

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

Podle návrhů autorů Caleb , pokud chcete řešení, které stále zobrazuje poslední pole , i když jich není přesně osm, můžete použít $NF.

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

Také pokud chcete výstup, aby se zachovaly oddělovače |, místo mezery můžete zadat oddělovače výstupního pole. Bohužel je to trochu neohrabanější než pouhé použití příznaku -F, ale zde jsou tři přístupy.

  • Můžete přiřadit vstup a oddělovače výstupních polí v awk samotném v BEGIN bloku.

    awk "BEGIN {FS = OFS = "|"} {print $1, $8}" logfile 
  • Tyto proměnné můžete přiřadit při volání awk z příkazového řádku pomocí příznaku -v.

    awk -v "FS=|" -v "OFS=|" "{print $1, $8}" logfile 
  • nebo jednoduše:

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

Komentáře

  • Dobrá práce, jak se tento problém dá zjednodušit. Můžete přidat poznámku o tom, jak použít | jako oddělovač výstupu místo výchozí prostor pro zřetězení řetězců. Můžete také vysvětlit, že k získání posledního sloupce použijte místo pevného kódování $NF $8.
  • poté, jak aktualizovat soubor?
  • @pankajprasad Napsat do nového souboru vtip h > poté přepsat starý nebo použít sponge. Toto je opravdu nová otázka.
  • @Sparhawk to funguje, ale vystružování obsahu je vymazáno. jak se s tím vypořádat?
  • @pankajprasad Musíte se zeptat na novou otázku. Klikněte na velké modré tlačítko nahoře s nápisem “ Položit otázku „.

Odpověď

Každopádně používáte awk:

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

Komentáře

  • Nebylo by nutné ‚ zadat oddělovač vstupního pole (protože v tomto případě se zdá, že být | spíše tímto prostorem) s -F\| nebo podobným? Také co kdyby chtěl použít stejný oddělovač pro výstup?
  • @Caleb Pravděpodobně: Čekal jsem, až OP potvrdí, jak přesně vypadal vstup, místo aby se snažil hádejte na základě nepracujících příkladů …
  • Všimněte si, že předpokládáme, že vstup obsahuje alespoň 2 pole.
  • @St é phaneChazelas OP jasně uvedl v kódu, že má vždy osm polí.
  • @ michaelb958 Myslím, že “ jasně “ nadhodnocuje případ, jen trochu 🙂

Odpovědět

Stačí nahradit z prvního na poslední | s | (případně mezerou):

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

Všimněte si, že ačkoli neexistuje žádná sed implementace, kde je | zvláštní (pokud je rozšířeno pravidelné výrazy nejsou povoleny prostřednictvím -E nebo v některých implementacích), \| je sám o sobě speciální v některých jako GNU sed. Měli byste tedy ne uniknout |, pokud chcete, aby odpovídal znaku |.

Pokud nahradíte mezerou a pokud vstup již může obsahovat řádky pouze s jedním |, budete s tím muset zacházet zvlášť jako |.*| na nich nebude odpovídat.Může to být:

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

(to znamená, že je .*| volitelná) Nebo:

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

nebo:

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

Pokud chcete první a osmé pole bez ohledu na počet polí v vstup, pak je to jen:

cut -d"|" -f1,8 

(všechny by za předpokladu vstupu fungovaly s jakýmkoli nástrojem kompatibilním s POSIXem) tvoří platný text (zejména sed obvykle nebudou fungovat, pokud má vstup bajty nebo sekvence bajtů, které nevytvářejí platné znaky v aktuálním národním prostředí, jako například printf "unix|St\351phane|Chazelas\n" | sed "s/|.*|/|/" v národním prostředí UTF-8)).

Odpověď

Pokud se ocitnete v nepořádku a bez sedu, můžete dosáhnout totéž s coreutils:

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

Komentáře

  • cut je čistší a kompaktnější než awk / sed, když vás zajímá pouze první sloupec, nebo pokud jsou pevně nastaveny oddělovače (tj. ne variabilní počet mezer).
  • Docela elegantní!

Odpověď

Vypadá to, že se pokoušíte získat první a poslední pole textu, která jsou ohraničena |.

Předpokládal jsem, že váš soubor protokolu obsahuje následující text,

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

A chcete výstup jako,

foo bar bar foo 

Pokud ano, pak přichází příkaz pro vaše „s

Prostřednictvím GNU sed,

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

Příklad:

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

Komentáře

  • Sloupce nejsou ohraničeny rourou | ale jsou ve sloupcích, zajímá mě použití sed, ale nepoužívám příkaz awk, jako jste to udělali ve svém příkazu: sed -r ‚ s ~ ^ ([^ |] *) . * \ | (. *) $ ~ \ 1 \ 2 ~ ‚ soubor
  • “ Sloupce jsou není ohraničen rourou | ale jsou ve sloupcích „, máte na mysli sloupce oddělené mezerami?
  • Ukázkový vstup a výstup by byly lepší.

Odpověď

Pravděpodobně byste to měli udělat s sed – stejně bych – ale jen protože tento ještě nikdo nenapsal:

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

VÝSTUP

 foo | bar 

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *