Jak uruchomić polecenie wiele razy, używając powłoki bash?


153

Czy istnieje sposób na uruchomienie polecenia (np. ps aux|grep someprocess) N razy?

Coś jak:

run -n 10  'ps aux|grep someprocess'

Chcę go używać interaktywnie, nie publikuj skryptów.

Aktualizacja: Powód, dla którego o to pytam, jest taki, że pracuję na wielu komputerach i nie chcę importować wszystkich moich skasowanych skryptów itp. Do każdego pudełka, aby uzyskać tę samą funkcjonalność na każdym komputerze.


Odpowiedzi:


197

Nie sądzę, żeby komenda lub wbudowana powłoka istniała w tym celu, ponieważ jest to trywialny podzbiór tego, do czego forprzeznaczona jest pętla Bourne'a, dlatego samodzielne wdrożenie takiego polecenia jest dość proste.

Na początek możesz użyć fikcyjnej forpętli:

for i in `seq 10`; do command; done

Lub równoważnie zgodnie z sugestią JimB, używając wbudowanego Bash do generowania sekwencji:

for i in {1..10}; do command; done

Powoduje to dziesięciokrotne wykonanie za commandkażdym razem - może to być potok lub seria poleceń oddzielonych przez ;lub &&. Możesz użyć tej $izmiennej, aby dowiedzieć się, w której iteracji się znajdujesz.

Jeśli uważasz, że ten jednowierszowy skrypt jest skryptu i dlatego z jakiegoś nieokreślonego (ale być może ważnego) powodu jest niepożądany, możesz go zaimplementować jako polecenie, być może coś takiego na swoim.

#function run
run() {
    number=$1
    shift
    for i in `seq $number`; do
      $@
    done
}

Stosowanie:

run 10 command

Przykład:

run 5 echo 'Hello World!'

16
@mahatmanich, Pętla nie jest skryptem. Nic nie stoi na przeszkodzie, aby używać ... w interaktywnym terminalu.
Zoredache

3
Cóż, powyższa linijka jest typowym sposobem na zrobienie tego i jest dość prosta. Dlaczego to nie jest dla ciebie dobre? Może zadajesz złe pytanie? Jaki jest główny cel twoich skryptów lub działań, które chcesz powtarzać kilka razy? Być może istnieje lepsze rozwiązanie, jeśli problem zostanie rozwiązany w inny sposób.
Patkos Csaba

6
@mahatmanich - for jest wbudowanym bash do iteracji.
JimB

3
@Eduardo Ivanec - FYI, bash ma wbudowany zakres, taki jak seq: {1..10}
JimB

1
Wygląda na to, że wbudowana sekwencja nawiasów nie obsługuje podstawiania zmiennych (patrz stackoverflow.com/a/3737773/713554 ). Podana funkcja działa idealnie, gdy zostanie umieszczona w opcji .bashrcif, jeśli {1..$number} zostanie wymieniona `seq $number`.
Leo

29

ps aux | grep someprocesswygląda na to, że chcesz oglądać zmiany programu przez określony czas. Eduardo udzielił odpowiedzi, która dokładnie odpowiada na twoje pytanie, ale istnieje alternatywa watch:

watch 'ps aux | grep someprocess'

Zauważ, że umieściłem polecenie w pojedynczych cudzysłowach, aby uniknąć interpretacji polecenia przez powłokę jako „uruchom zegarek ps aux” i przepuszczaj wynik grep someprocess. Innym sposobem wykonania poprzedniego polecenia byłoby:

watch ps aux \| grep someprocess

Domyślnie watchodświeża się co dwie sekundy, które można zmienić za pomocą -nopcji. Na przykład, jeśli chcesz mieć odstęp 1 sekundy:

watch -n 1 'ps aux | grep someprocess'

21

Dla żartu

pgrep ssh ;!!;!!;!!;!!;!!;!!

Czy ktoś może to wytłumaczyć? Wygląda bardzo intrygująco.
Daniel Vartanov

4
; jest tylko separatorem poleceń. !! powtórz ostatnie polecenie w bash. Więc uruchom 'pgrep ssh', a następnie powtórz go 6 razy.
Piotr Kukielka,

Chociaż jest to pouczające, nie jest bardzo intuicyjne. One-liner forwydaje się najlepszym sposobem. W każdym razie dzięki za odpowiedź.
erm3nda

1
Czy cmd ;!!w jednej linii nie powtórzysz polecenia wprowadzonego przed bieżącą linią? Musiałyby to być dwa osobne historywpisy.
Joel Purra

wymienić ;z &&zatrzymać się na pierwszym niepowodzeniu.
user881300,

16

podobne do poprzednich odpowiedzi, ale nie wymaga pętli for:

seq 10 | xargs -I -- echo "hello"

wyjście potoku seq do xargs bez argumentów ani opcji


2
Spowoduje to tylko jedno wykonanie echo "hello" 1 2 3 4 5 6 7 8 9 10. Musisz uruchomić xargs z -n 1dla jednego procesu dla każdego wejścia (liczby) i -P 10dla równoległego wykonywania (10 równoległych procesów). Kończąc z seq 10 | xargs -n 1 -P 10 echo.
Alexander Klimetschek

16

Spróbuj tego:

yes ls | head -n5 | bash

Wymaga to wykonania polecenia w podpowłoce, co stanowi niewielki spadek wydajności. YMMV. Zasadniczo dostajesz polecenie „tak”, aby powtórzyć ciąg „ls” N razy; podczas gdy „head -n5” zakończył pętlę w 5 powtórzeniach. Ostatnia rura wysyła polecenie do wybranej powłoki.

Nawiasem mówiąc csh, powłoki mają wbudowane repeatpolecenie. Możesz go użyć do wykonania polecenia w podpowłoce bash!


5

Sposób POSIX

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_04_01

x=10
while [ $x -gt 0 ]; do
    command
    x=$(($x-1))
done

który można oczywiście przekształcić w jedną wkładkę:

x=10; while [ $x -gt 0 ]; do command; x=$(($x-1)); done

i wydaje się być najbardziej przenośnym sposobem, a tym samym mniejszym prawdopodobieństwem sprawi, że instalujesz programy.

Poniższe są mniej przenośne:

  • interpretacja nawiasów {1..10}: specyficzna dla bash, i generowałaby ogromną linię, jeśli argument jest duży
  • seq: GNU
  • yes: GNU

A jeśli zmęczy Cię przenośność, rozważ GNU parallel:

sudo apt-get install parallel
seq 100 | parallel echo {}

który uruchamia polecenia równolegle i ma wiele fajnych opcji.

Zobacz także: https://stackoverflow.com/questions/169511/how-do-i-iterate-over-a-range-of-numbers-defined-by-variables-in-bash


GNU Parallel jest zbudowany tak, aby był bardzo przenośny. sh, zsh, kshi bashwszystkie są dobrze obsługiwane na większości platform. csh, tcsh, fishma pewne wsparcie. Za pomocą parallel --embedmożesz nawet zbudować skrypt, który można łatwo przenieść do innego systemu, w którym nie ma zainstalowanego GNU Parallel.
Ole Tange

2

Implementacja powłoki ryby powyższejrun funkcji @ eduardo-ivanec

function run
  set number $argv[1]
  for i in (seq $number)
    eval $argv[2..-1]
  end
end

0

Byłby to „zegarek” - powinien być częścią prawie każdego systemu uniksowego używającego procps

Możesz zobaczyć zmiany w systemie lub inny interesujący ruch w systemie. Na przykład,

watch "df -hP | grep /tmp" 

Po prostu umieść swoje komendy jako argument (patrz man watch)


Jest już odpowiedź z zegarkiem ... patrz tuż poniżej ...
mahatmanich

0

W systemie macOS możesz użyć repeatpolecenia.

repeat 10 ps aux | grep someprocess
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.