Potrzebuję pomocy, aby dowiedzieć się, jak użyć polecenia sed, aby wyświetlić tylko pierwszą i ostatnią kolumnę w pliku tekstowym. Oto co mam do tej pory dla kolumny 1:
cat logfile | sed "s/\|/ /"|awk "{print $1}"
Moja słaba próba wyświetlenia ostatniej kolumny była następująca:
cat logfile | sed "s/\|/ /"|awk "{print $1}{print $8}"
Jednak pobiera to pierwszą i ostatnią kolumnę i łączy je w jedną listę. Czy istnieje sposób na wyraźne wydrukowanie pierwszej i ostatniej kolumny za pomocą poleceń sed i awk?
Przykładowe dane wejściowe:
foo|dog|cat|mouse|lion|ox|tiger|bar
Komentarze
- Podaj przykładowe dane wejściowe.
Odpowiedź
Prawie gotowe. Po prostu umieść oba odwołania do kolumn obok siebie.
cat logfile | sed "s/|/ /" | awk "{print $1, $8}"
Pamiętaj też, że nie potrzebujesz tutaj cat
.
sed "s/|/ /" logfile | awk "{print $1, $8}"
Pamiętaj też, że możesz powiedzieć awk
, że separatory kolumn to |
zamiast spacji, więc nie potrzebujesz też sed
.
awk -F "|" "{print $1, $8}" logfile
Zgodnie z sugestiami Caleb , jeśli potrzebujesz rozwiązania, które nadal wyświetla ostatnie pole , nawet jeśli nie ma dokładnie ośmiu, możesz użyć $NF
.
awk -F "|" "{print $1, $NF}" logfile
Ponadto, jeśli chcesz dane wyjściowe, aby zachować separatory |
, zamiast używać spacji, można określić separatory pól wyjściowych. Niestety, jest to trochę bardziej niezgrabne niż użycie flagi -F
, ale oto trzy podejścia.
-
Możesz przypisać dane wejściowe i separatory pól wyjściowych w samym
awk
, w bloku BEGIN.awk "BEGIN {FS = OFS = "|"} {print $1, $8}" logfile
-
Możesz przypisać te zmienne, wywołując
awk
z wiersza poleceń, za pomocą flagi-v
.awk -v "FS=|" -v "OFS=|" "{print $1, $8}" logfile
-
lub po prostu:
awk -F "|" "{print $1 "|" $8}" logfile
Komentarze
- Dobra robota, jak wyjaśnić, jak można uprościć ten problem. Możesz dodać uwagę dotyczącą używania elementu
|
jako separatora danych wyjściowych zamiast domyślne miejsce na konkatenację ciągów. Możesz również wyjaśnić, jak używać$NF
zamiast sztywnego kodowania$8
, aby uzyskać ostatnią kolumnę. - po tym jak zaktualizować plik?
- @pankajprasad Zapisz do nowego pliku wit h
>
, a następnie nadpisz stary lub użyjsponge
. To jest naprawdę nowe pytanie. - @Sparhawk to działa, ale rozwiercanie zawartości jest wymazane. jak sobie z tym poradzić?
- @pankajprasad Musisz zadać nowe pytanie. Kliknij duży niebieski przycisk u góry z napisem ” Zadaj pytanie „.
Odpowiedź
Mimo wszystko używasz awk
:
awk "{ print $1, $NF }" file
Komentarze
- Nie ' t musisz określić separator pola wejściowego (ponieważ w tym przypadku wydaje się, że być
|
raczej tą spacją) z-F\|
lub podobnym? A co by było, gdyby chciał użyć tego samego separatora do wyjścia? - @Caleb Prawdopodobnie: czekałem na OP, aby potwierdzić, jak dokładnie wyglądało wejście, zamiast próbować zgadnij na podstawie niedziałających przykładów …
- Zauważ, że przy założeniu, że dane wejściowe zawierają co najmniej 2 pola.
- @St é phaneChazelas OP jasno określił w kodzie, że ma zawsze osiem pól.
- @ michaelb958 Myślę, że ” wyraźnie ” przesadza, tylko trochę 🙂
Odpowiedź
Po prostu zamień od pierwszej do ostatniej |
z |
(lub spacją, jeśli wolisz):
sed "s/|.*|/|/"
Zauważ, że chociaż nie ma implementacji sed
, w której |
jest specjalne (o ile rozszerzone zwykłe wyrażenia nie są włączane przez -E
lub w niektórych implementacjach), samo \|
jest wyjątkowe w niektórych, takich jak GNU sed
. Dlatego nie powinieneś zmieniać znaczenia |
, jeśli chcesz dopasować znak |
.
Jeśli zamieniasz na spację i jeśli dane wejściowe mogą już zawierać wiersze zawierające tylko jeden |
, to „będziesz musiał traktować to specjalnie jako |.*|
nie gra na nich.Może to być:
sed "s/|\(.*|\)\{0,1\}/ /"
(oznacza to, że .*|
część jest opcjonalna) Lub:
sed "s/|.*|/ /;s/|/ /"
lub:
sed "s/\([^|]*\).*|/\1 /"
Jeśli chcesz, aby pierwsze i ósme pola bez względu na liczbę pól w dane wejściowe, to po prostu:
cut -d"|" -f1,8
(wszystko to działałoby z każdym narzędziem zgodnym z POSIX przy założeniu, że dane wejściowe formularze prawidłowy tekst (w szczególności te sed
generalnie nie będą działać, jeśli dane wejściowe zawierają bajty lub sekwencje bajtów, które nie tworzą poprawnych znaków w bieżącym ustawieniu regionalnym, jak na przykład printf "unix|St\351phane|Chazelas\n" | sed "s/|.*|/|/"
w lokalizacji UTF-8)).
Odpowiedź
Jeśli okaże się, że jesteś bez awk i sed, możesz osiągnąć to samo z coreutils:
paste <( cut -d"|" -f1 file) \ <(rev file | cut -d"|" -f1 | rev)
Komentarze
-
cut
jest czystszy i bardziej zwarty niż awk / sed, jeśli interesuje nas tylko pierwsza kolumna lub jeśli ograniczniki są stałe (tj. nie są zmienną liczbą spacji). - Całkiem eleganckie!
Odpowiedź
Wygląda na to, że próbujesz uzyskać pierwsze i ostatnie pola tekstu, które są rozdzielone |
.
Założyłem, że twój plik dziennika zawiera tekst taki jak poniżej,
foo|dog|cat|mouse|lion|ox|tiger|bar bar|dog|cat|mouse|lion|ox|tiger|foo
I chcesz wyjście takie jak,
foo bar bar foo
Jeśli tak, to oto polecenie dla twoich „s
Poprzez GNU sed
sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" file
Przykład:
$ echo "foo|dog|cat|mouse|lion|ox|tiger|bar" | sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" foo bar
Komentarze
- Kolumny nie są rozdzielane pionową kreską | ale są w kolumnach, interesuje mnie użycie seda, ale nie użycie polecenia awk, tak jak w przypadku polecenia: sed -r ' s ~ ^ ([^ |] *) . * \ | (. *) $ ~ \ 1 \ 2 ~ ' plik
- ” Kolumny są nie jest ograniczony potokiem | ale są w kolumnach „, masz na myśli, że kolumny są oddzielone spacjami?
- Przykładowe wejście i wyjście byłoby lepsze.
Odpowiedź
Prawdopodobnie powinieneś to zrobić za pomocą sed
– tak czy owak – ale tylko ponieważ nikt jeszcze tego nie napisał:
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