Jeg har brug for hjælp til at finde ud af, hvordan man bruger kommandoen sed til kun at vise den første kolonne og den sidste kolonne i en tekstfil. Her er hvad jeg hidtil har til kolonne 1:
cat logfile | sed "s/\|/ /"|awk "{print $1}"
Mit svage forsøg på at få den sidste kolonne til at vise også var:
cat logfile | sed "s/\|/ /"|awk "{print $1}{print $8}"
Dette tager dog den første kolonne og sidste kolonne og fletter dem sammen i en liste. Er der en måde at udskrive den første kolonne og sidste kolonne tydeligt med sed- og awk-kommandoer?
Eksempelindgang:
foo|dog|cat|mouse|lion|ox|tiger|bar
Kommentarer
- Angiv nogle eksempler på input.
Svar
Næsten der. Sæt bare begge kolonnereferencer ved siden af hinanden.
cat logfile | sed "s/|/ /" | awk "{print $1, $8}"
Bemærk også, at du ikke har brug for cat
her .
sed "s/|/ /" logfile | awk "{print $1, $8}"
Bemærk også, at du kan fortælle awk
, at søjleseparatorerne er |
i stedet for mellemrum, så du behøver heller ikke sed
.
awk -F "|" "{print $1, $8}" logfile
I henhold til forslag af Caleb , hvis du vil have en løsning, der stadig udsender det sidste felt , selvom der ikke er nøjagtigt otte, kan du bruge $NF
.
awk -F "|" "{print $1, $NF}" logfile
Også hvis du vil have output for at bevare |
separatorer, i stedet for at bruge et mellemrum kan du angive outputfeltadskillere. Desværre er det “lidt mere klodset end blot at bruge -F
-flagget, men her er tre tilgange.
-
Du kan tildele input og outputfeltadskillere i
awk
i BEGIN-blokken.awk "BEGIN {FS = OFS = "|"} {print $1, $8}" logfile
-
Du kan tildele disse variabler, når du ringer til
awk
fra kommandolinjen via flagget-v
.awk -v "FS=|" -v "OFS=|" "{print $1, $8}" logfile
-
eller simpelthen:
awk -F "|" "{print $1 "|" $8}" logfile
Kommentarer
- Godt arbejde med at nedbryde, hvordan dette problem kan forenkles. Du kan tilføje en note om, hvordan du bruger
|
som outputudskiller i stedet for standard plads til streng sammenkædning. Du kan også forklare at bruge$NF
i stedet for hårdkodning$8
for at få den sidste kolonne. - derefter hvordan opdateres filen?
- @pankajprasad Skriv til en ny fil med h
>
skriv derefter den gamle over, eller brugsponge
. Dette er dog virkelig et nyt spørgsmål. - @Sparhawk det virker, men reaming-indhold slettes. hvordan skal man håndtere det?
- @pankajprasad Du skal stille et nyt spørgsmål. Klik på den store blå knap øverst, der siger ” Stil spørgsmål “.
Svar
Du bruger awk
alligevel:
awk "{ print $1, $NF }" file
Kommentarer
- Ville ‘ t skal du specificere inputfeltadskilleren (da det i dette tilfælde ser ud til at være
|
snarere det mellemrum) med-F\|
eller lignende? Også hvad hvis han ville bruge den samme afgrænser til output? - @Caleb Sandsynligvis: Jeg ventede på, at OP skulle bekræfte, hvordan nøjagtigt input lignede, snarere end at prøve at gæt baseret på de ikke-fungerende eksempler …
- Bemærk, at det forudsættes, at input indeholder mindst 2 felter.
- @St é phaneChazelas OP angav tydeligt i kode, at det altid har otte felter.
- @ michaelb958 Jeg synes ” klart ” overvurderer sagen, bare lidt 🙂
Svar
Erstat bare fra første til sidste |
med en |
(eller mellemrum hvis du foretrækker det):
sed "s/|.*|/|/"
Bemærk, at selvom der ikke er sed
implementering, hvor |
er speciel (så længe udvidet regelmæssigt udtryk er ikke aktiveret via -E
eller i nogle implementeringer), \|
i sig selv er speciel i nogle som GNU sed
. Så du bør ikke undslippe |
hvis du har til hensigt at det skal matche |
-tegnet.
Hvis du udskifter med mellemrum, og hvis input allerede muligvis indeholder linjer med kun |
, skal du behandle det specielt som |.*|
vandt ikke match på disse.Det kunne være:
sed "s/|\(.*|\)\{0,1\}/ /"
(det vil sige at .*|
-delen er valgfri) Eller:
sed "s/|.*|/ /;s/|/ /"
eller:
sed "s/\([^|]*\).*|/\1 /"
Hvis du vil have det første og det ottende felt uanset antallet af felter i input, så er det bare:
cut -d"|" -f1,8
(alle dem vil arbejde med ethvert POSIX-kompatibelt værktøj, forudsat at input danner gyldig tekst (især sed
dem fungerer normalt ikke, hvis input har bytes eller sekvenser af bytes, der ikke danner gyldige tegn i det aktuelle sprog som f.eks. printf "unix|St\351phane|Chazelas\n" | sed "s/|.*|/|/"
i et UTF-8-sprog)).
Svar
Hvis du finder dig selv ubehagelig og sed-mindre, kan du opnå samme ting med kerneudstyr:
paste <( cut -d"|" -f1 file) \ <(rev file | cut -d"|" -f1 | rev)
Kommentarer
-
cut
er renere og mere kompakt end awk / sed, når du bare er interesseret i den første kolonne, eller hvis afgrænsningerne er faste (dvs. ikke et variabelt antal mellemrum). - Temmelig elegant!
Svar
Det ser ud til, at du prøver at få det første og sidste felt i tekst, der er afgrænset af |
.
Jeg antog, at din logfil indeholder teksten som nedenfor,
foo|dog|cat|mouse|lion|ox|tiger|bar bar|dog|cat|mouse|lion|ox|tiger|foo
Og du vil have output ligesom,
foo bar bar foo
Hvis ja, så kommer kommandoen til dine “s
Gennem GNU sed,
sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" file
Eksempel:
$ echo "foo|dog|cat|mouse|lion|ox|tiger|bar" | sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" foo bar
Kommentarer
- Kolonnerne afgrænses ikke af et rør | men de er i kolonner, jeg er interesseret i at bruge sed, men ikke at bruge kommandoen awk som du gjorde i din kommando: sed -r ‘ s ~ ^ ([^ |] *) . * \ | (. *) $ ~ \ 1 \ 2 ~ ‘ fil
- ” Kolonnerne er ikke afgrænset af et rør | men de er i kolonner “, mener du kolonner er adskilt af mellemrum?
- En prøveindgang og en output ville være bedre.
Svar
Du skulle sandsynligvis gøre det med sed
– jeg ville alligevel – men bare fordi ingen har skrevet denne endnu:
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