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žítsponge
. 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