Jak użyć polecenia powłoki, aby wyświetlić tylko pierwszą i ostatnią kolumnę w pliku tekstowym?

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żyj sponge. 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 

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *