Zakładając prosty grep, taki jak:
$ psa aux | grep someApp
1000 11634 51.2 0.1 32824 9112 pts/1 SN+ 13:24 7:49 someApp
Zapewnia to wiele informacji, ale ponieważ brakuje pierwszego wiersza polecenia ps, nie ma kontekstu dla informacji. Wolałbym, aby wyświetlana była również pierwsza linia ps:
$ psa aux | someMagic someApp
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
1000 11634 51.2 0.1 32824 9112 pts/1 SN+ 13:24 7:49 someApp
Oczywiście mogę dodać wyrażenie regularne do grep specjalnie dla ps:
$ ps aux | grep -E "COMMAND|someApp"
Wolałbym jednak bardziej ogólne rozwiązanie, ponieważ istnieją inne przypadki, w których chciałbym mieć również pierwszą linię.
Wydaje się, że byłby to dobry przypadek użycia deskryptora pliku „stdmeta” .
bash
command-line
dotancohen
źródło
źródło
ack
są tak użyteczne i dlaczegoperl
zdrożała przeszłośćsed
,awk
itp popularność: to ważne dla części podsumować w spójną całość.-C
argumentu dops
i nie trzeba go było potokować do grep. np.ps u -C someApp
lub nawetps u -C app1 -C app2 -C app3
ps aux | { head -1; grep foo; }
wspomnianego przez @Nahuela Fouilleula poniżej (jego prawdopodobnie jest to jedyne rozwiązanie, które mógłbym w razie potrzeby przypomnieć na miejscu)Odpowiedzi:
Dobry sposób
Zwykle nie możesz tego zrobić za pomocą grep, ale możesz użyć innych narzędzi. Wspomniano już o AWK, ale możesz także użyć
sed
takiego:Jak to działa:
Narzędzie Sed działa indywidualnie dla każdej linii, uruchamiając określone polecenia na każdym z nich. Możesz mieć wiele poleceń, określając kilka
-e
opcji. Do każdego polecenia możemy dołączyć parametr zakresu określający, czy to polecenie powinno być zastosowane do określonej linii, czy nie.„1p” to pierwsze polecenie. Używa
p
polecenia, które normalnie drukuje wszystkie linie. Ale poprzedzamy go wartością liczbową, która określa zakres, do którego należy ją zastosować. Tutaj używamy,1
co oznacza pierwszą linię. Jeśli chcesz wydrukować więcej linii, możesz użyćx,yp
gdziex
pierwsza linia do wydrukowania,y
ostatnia linia do wydrukowania. Na przykład do wydrukowania pierwszych 3 wierszy użyłbyś1,3p
Następne polecenie to
d
normalnie usuwające wszystkie linie z bufora. Przed tym poleceniem umieszczamyyourpattern
między dwoma/
znakami. Jest to inny sposób (po pierwsze, aby określić, które linie, tak jak to zrobiliśmy zp
poleceniem), adresowania linii, w których polecenie powinno być uruchomione. Oznacza to, że polecenie będzie działać tylko dla pasujących liniiyourpattern
. Poza tym używamy!
znaku przedd
poleceniem, które odwraca jego logikę. Teraz usunie wszystkie linie, które nie pasują do określonego wzorca.Na końcu sed wydrukuje wszystkie linie pozostawione w buforze. Ale usunęliśmy z bufora linie, które nie pasują, więc zostaną wydrukowane tylko pasujące linie.
Podsumowując: drukujemy 1. linię, a następnie usuwamy z linii wszystkie linie, które nie pasują do naszego wzorca. Reszta linii jest drukowana (więc tylko linie, które pasują do wzoru).
Problem z pierwszej linii
Jak wspomniano w komentarzach, istnieje problem z tym podejściem. Jeśli określony wzór pasuje również do pierwszego wiersza, zostanie wydrukowany dwukrotnie (raz na
p
polecenie i raz z powodu dopasowania). Możemy tego uniknąć na dwa sposoby:Dodanie
1d
polecenia po1p
. Jak już wspomniałem,d
polecenie usuwa wiersze z bufora, a my określamy jego zakres liczbą 1, co oznacza, że usunie tylko pierwszą linię. Tak byłoby poleceniesed -e '1p' -e '1d' -e '/youpattern/!d'
Za pomocą
1b
polecenia zamiast1p
. To jest trik.b
polecenie pozwala nam przejść do innego polecenia określonego przez etykietę (w ten sposób niektóre polecenia można pominąć). Ale jeśli ta etykieta nie jest określona (jak w naszym przykładzie), po prostu przeskakuje na koniec poleceń, ignorując pozostałe polecenia dla naszej linii. W naszym przypadku ostatnied
polecenie nie usunie tej linii z bufora.Pełny przykład:
Używanie średnika
Niektóre
sed
implementacje mogą zaoszczędzić ci trochę pisania, używając średnika do oddzielania poleceń zamiast wielu-e
opcji. Jeśli więc nie zależy ci na przenośności, polecenie będzie takieps aux | sed '1b;/syslog/!d'
. Działa przynajmniejGNU sed
ibusybox
implementacje.Szalony sposób
Oto jednak dość szalony sposób na zrobienie tego z grep. To zdecydowanie nie jest optymalne, publikuję to tylko w celach edukacyjnych, ale możesz go użyć na przykład, jeśli nie masz innego narzędzia w systemie:
Jak to działa
Najpierw używamy
-n
opcji, aby dodać numery linii przed każdą linią. Chcemy numerować wszystkie linie, które pasujemy.*
- cokolwiek, nawet pustą linię. Jak sugerujemy w komentarzach, możemy również dopasować „^”, wynik jest taki sam.Następnie używamy rozszerzonych wyrażeń regularnych, abyśmy mogli użyć
\|
znaku specjalnego, który działa jak OR. Dopasowujemy więc, jeśli linia zaczyna się od1:
(pierwsza linia) lub zawiera nasz wzorzec (w tym przypadku jest tosyslog
).Problem z numerami linii
Teraz problem polega na tym, że otrzymujemy te brzydkie numery wierszy w naszych wynikach. Jeśli jest to problem, możemy je usunąć za pomocą
cut
:-d
opcja określa separator,-f
określa pola (lub kolumny), które chcemy wydrukować. Dlatego chcemy wyciąć każdą linię na każdym:
znaku i wydrukować tylko drugą i wszystkie kolejne kolumny. To skutecznie usuwa pierwszą kolumnę ze swoim separatorem i właśnie tego potrzebujemy.źródło
cat -n
i wyglądałaby wyraźniej, jak w przypadku nadużywania grep.nl
nie zlicza pustych linii (ale drukuje je bez numeru linii),cat -n
formatuje numerację z poprzedzającymi spacjami,grep -n .
w ogóle usuwa puste linie i dodaje dwukropek. Wszystkie mają swoje ... eee ... cechy ;-)ps aux | sed '1p;/pattern/!d'
wydrukuje pierwszą linię dwa razy, jeśli pasuje do wzorca . Najlepiej jest używaneb
polecenie:ps aux | sed -e 1b -e '/pattern/!d'
.cat -n
nie jest POSIX.grep -n '^'
numerowałby każdą linię (nie jest to problem z wyjściem ps, który nie ma pustych linii).nl -ba -d $'\n'
numeruje każdą linię.1b;...
nie jest przenośny ani POSIX, po "b" nie może być żadnych innych poleceń, więc potrzebujesz nowego wiersza lub innego wyrażenia -e.Co myślisz o używaniu
awk
zamiastgrep
?NR == 1
: Liczba rekordów == 1; to znaczy. pierwsza linia||
: lub:/syslogd/
: Wzór do wyszukaniaWarto też przyjrzeć się temu
pgrep
, choć dotyczy to raczej skryptów, a nie danych wyjściowych użytkownika. Pozwala to jednak uniknąćgrep
pojawienia się samego polecenia na wyjściu.źródło
EDYCJA: po komentarzach
Myślałem, że
head -1
przeczytam wszystkie dane wejściowe, ale po przetestowaniu to też działa.wyjście jest
źródło
{ IFS='' read line; ... }
na wypadek, gdyby nagłówek zaczynał się od spacji.head -1
zamiast kombinacji odczytu / echa.head -n1
moim bash. Prawdopodobnie może to być specyficzne dla implementacji. Moja głowa nie czyta w tym przypadku całego wejścia, tylko pierwszy wiersz, pozostawiając resztę w buforze wejściowym.head -n1
jest krótszy, ale wydaje się, że nawet specyfikacja POSIX milczy co do tego, ile jego danych wejściowych może odczytać, więc być możeread line; echo $line
jest w końcu bardziej przenośny.Ps obsługuje wewnętrzny filtr,
Załóżmy, że szukasz procesu bash:
ps -C bash -f
Wyświetla listę wszystkich procesów o tej nazwie
bash
.źródło
Zwykle wysyłam nagłówek do stderr :
Zazwyczaj wystarcza to do czytania przez ludzi. na przykład:
Część w nawiasach może przejść do własnego skryptu do ogólnego użytku.
Dodatkową wygodą jest to, że dane wyjściowe można dalej potokować (do
sort
itp.), A nagłówek pozostanie na górze.źródło
Możesz także użyć
tee
ihead
:Należy jednak pamiętać, że dopóki
tee
nie można zignorowaćSIGPIPE
sygnałów (patrz np. Dyskusja tutaj ), takie podejście wymaga obejścia, aby być wiarygodnym. Obejściem tego problemu jest ignorowanie sygnałów SIGPIPE, można to na przykład zrobić w ten sposób w powłokach typu bash:Należy również pamiętać, że kolejność wydruków nie jest gwarantowana .
źródło
grep
:| { sleep .5; cat }
.Być może dwie
ps
komendy byłyby najłatwiejsze.źródło
ps aux
połączeniem ... A jeśli chcesz tylko tę statyczną pierwszą linię, dlaczego nie wykonać echa ręcznie?Możesz użyć pidstat z:
Przykład:
Więcej informacji: http://linux.die.net/man/1/pidstat
źródło
Najpierw umieść w pliku .bashrc lub skopiuj / wklej w powłoce, aby przetestować.
Zastosowanie: psls [grep pattern]
Upewnij się, że źródło .bashrc (lub .bash_profile, jeśli go tam umieścisz):
Funkcja zakończy się nawet automatycznie w wierszu poleceń powłoki. Jak powiedziałeś w innej odpowiedzi, możesz potokować pierwszą linię do pliku, aby zapisać jedno wywołanie do ps.
źródło
psl
, która dzwoni tylko razps
igrep
raz (i nie potrzebujehead
).sortuj, ale zachowaj nagłówek na górze
I użyj tego w ten sposób
źródło
Dzięki głównie Janisowi Papanagnou w comp.unix.shell korzystam z następującej funkcji:
Ma to wiele zalet:
-i
do dopasowywania bez rozróżniania wielkości liter,-E
dla rozszerzonych wyrażeń regularnych itp.Przykład użycia:
źródło
Innym sposobem jest
gnu ed
:lub jeśli powłoka obsługuje podstawianie procesów:
to jest:
Bardziej przenośny, bez
gnu
'!'
podstawienia lub powłoki - używając tylkoed
wbudowanego,r
abyr
wprowadzić dane wyjścioweps aux
do bufora, a następnie usunąć niepasujące wiersze w2,$
zakresie i wydrukować wynik:A ponieważ
sed
polecenia w zaakceptowanej odpowiedzi generują również wiersz pasujący do siebie, zsed
obsługującą-f-
i powłoką obsługującą podstawianie procesów, uruchomiłbym:który w zasadzie robi to samo co poprzednie
ed
polecenia.źródło
Sposób Perla:
O wiele łatwiejszy do odczytania niż
sed
szybszy, bez ryzyka wybrania niepożądanych linii.źródło
Jeśli dotyczy to tylko procesów grepowania z pełnymi nagłówkami, rozwinąłbym sugestię @ mrb:
pgrep bash | xargs ps -fp
uzyska ten sam wynik, ale bez podpowłoki. Jeśli wymagane jest inne formatowanie:źródło
Jeśli znasz dokładne numery wierszy, perl to łatwe! Jeśli chcesz pobrać wiersz 1 i 5 z pliku, powiedz / etc / passwd:
Jeśli chcesz uzyskać także inne wiersze, po prostu dodaj ich liczby do tablicy.
źródło