Vraag Hoe een opdracht meerdere keren uitvoeren, met behulp van bash shell?


Is er een manier om een ​​opdracht uit te voeren (bijv. ps aux|grep someprocess) voor n tijden?

Zoiets als:

run -n 10  'ps aux|grep someprocess'

Ik wil het interactief gebruiken, plaats geen scripts.

Update: de reden dat ik dit vraag, is dat ik op veel machines werk en dat ik niet al mijn aangepaste scripts, enz. In elke box wil importeren om dezelfde functionaliteit op elke machine te krijgen.


132
2018-05-24 15:55


oorsprong


Geweldig dat het antwoord zoveel upvotes krijgt zonder de vraag er zelfs maar één te ontvangen. Laten we dat veranderen +1 :) - Lekensteyn
@Lekensteyn bedankt - mahatmanich
stackoverflow.com/questions/3737740/... - Ciro Santilli 新疆改造中心 六四事件 法轮功


antwoorden:


Ik denk niet dat hiervoor een commando of shell is gebouwd, omdat het een triviale deelverzameling is van wat de Bourne-shell is for lus is ontworpen voor en het uitvoeren van een dergelijke opdracht is daarom vrij eenvoudig.

Om te beginnen kun je een dummy gebruiken for lus:

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

Of equivalent volgens de suggestie van JimB, waarbij de ingebouwde Bash werd gebruikt voor het genereren van reeksen:

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

Dit herhaalt tien keer uitvoeren command elke keer - het kan een pipe zijn of een reeks commando's gescheiden door ; of &&. U kunt de $i variabele om te weten in welke iteratie je zit.

Als je deze one-liner als een script beschouwt en dus voor een niet-gespecificeerde (maar misschien wel geldige) reden niet wenselijk bent, kun je het als een opdracht implementeren, misschien iets als dit op je .bashrc (niet getest):

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

Gebruik:

run 10 command

Voorbeeld:

run 5 echo 'Hello World!'

170
2018-05-24 15:57



@mahatmanich, Een lus is geen script. Er is niets wat u belet om te gebruiken voor ... op een interactieve terminal. - Zoredache
Welnu, de enige voering hierboven is het soort standaardmanier om het te doen en het is vrij eenvoudig. Waarom is het niet goed voor jou? Misschien stel je de verkeerde vraag? Wat is het belangrijkste doel van uw scripts of uw acties dat u ze een aantal keren wilt herhalen? Misschien is er een betere oplossing als we het probleem op een andere manier stellen. - Patkos Csaba
@mahatmanich - for  is de ingebouwde bash voor iteratie. - JimB
@Eduardo Ivanec - FYI, bash heeft een ingebouwde reeks zoals seq: {1..10} - JimB
Het lijkt erop dat de ingebouwde bracket-reeks geen ondersteuning biedt voor variabele substitutie (zie stackoverflow.com/a/3737773/713554). De functie die je hebt gegeven werkt perfect wanneer je hem plaatst .bashrc als {1..$number} wordt ingeruild voor `seq $number` though. - Leo


ps aux | grep someprocess het lijkt erop dat je een programma voor een bepaalde tijd wilt bekijken. Eduardo gaf een antwoord dat je vraag exact beantwoordde, maar er is een alternatief: watch:

watch 'ps aux | grep someprocess'

Merk op dat ik de opdracht in enkele aanhalingstekens heb geplaatst om te voorkomen dat de shell de opdracht interpreteert als "run watch ps aux" en het resultaat doorspant grep someprocess. Een andere manier om het vorige commando uit te voeren zou zijn:

watch ps aux \| grep someprocess

Standaard, watch wordt elke twee seconden vernieuwd, die kan worden gewijzigd met behulp van de -n keuze. Als u bijvoorbeeld een interval van 1 seconde wilt hebben:

watch -n 1 'ps aux | grep someprocess'

29
2018-05-26 15:07



Ja, dit werkt als een charme. - Jānis Gruzis


Voor de lol

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

21
2018-06-27 13:04



Kan iemand dit uitleggen alstublieft? Ziet er heel intrigerend uit. - Daniel Vartanov
; is gewoon opdrachtscheidingsteken. !! herhaal het laatste commando in bash. Dus voer deze 'pgrep ssh' uit en herhaal hem dan 6 keer. - Piotr Kukielka
Hoewel dat leerzaam is, is het niet handig intuïtief. Oneliner for lijkt de beste manier. Bedankt voor het antwoord. - erm3nda
zal niet cmd ;!! herhaal op één regel de ingevoerde opdracht voor de huidige regel? Het zou twee gescheiden moeten zijn history inzendingen. - Joel Purra


Probeer dit:

yes ls | head -n5 | bash

Dit vereist dat de opdracht wordt uitgevoerd in een sub-shell, een lichte prestatieboete. YMMV. In principe krijg je het "ja" -commando om de string "ls" N keer te herhalen; terwijl "head -n5" de lus beëindigde bij 5 herhalingen. De laatste pijp zendt het commando naar de shell van je keuze.

toevallig csh-achtige shells hebben een ingebouwde repeat commando. Je zou dat kunnen gebruiken om je commando uit te voeren in een bash sub-shell!


14
2018-01-31 00:04





vergelijkbaar met eerdere antwoorden, maar vereist geen for-lus:

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

pijpuitvoer van seq naar xargs zonder argumenten of opties


11
2017-11-18 14:36



Dit zal slechts één uitvoering uitvoeren echo "hello" 1 2 3 4 5 6 7 8 9 10. Je moet xargs uitvoeren met -n 1 voor één proces voor elke invoer (nummer) en met -P 10 voor parallelle uitvoering (10 parallelle processen). Eindigend met seq 10 | xargs -n 1 -P 10 echo. - Alexander Klimetschek


POSIX manier

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

wat natuurlijk in één lijn zou kunnen worden gemaakt:

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

en lijkt de meest draagbare manier te zijn, en dus minder waarschijnlijk om je programma's te laten installeren.

De volgende zijn minder draagbaar:

  • steun uitbreiding {1..10}: bash specifiek, en zou een enorme regel genereren als het argument groot is
  • seq: GNU
  • yes: GNU

En als je moe bent van portabiliteit, overweeg dan GNU parallel:

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

die commando's parallel uitvoert en veel coole opties heeft.

Zie ook: https://stackoverflow.com/questions/169511/how-do-i-iterate-over-a-range-of-numbers-defined-by-variables-in-bash


4
2018-06-15 09:39





Een fish shell-implementatie van @ eduardo-ivanec's run functie bovenstaande

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

2
2018-06-20 18:44