क्या bash में कमांड N चलाने का एक बेहतर तरीका है?


304

मैं कभी-कभी इस तरह से एक bash कमांड लाइन चलाता हूं:

n=0; while [[ $n -lt 10 ]]; do some_command; n=$((n+1)); done

some_commandएक पंक्ति में कई बार चलाने के लिए - इस मामले में 10 बार।

अक्सर some_commandवास्तव में कमांड या पाइपलाइन की एक श्रृंखला होती है।

क्या ऐसा करने का अधिक संक्षिप्त तरीका है?


1
अन्य अच्छे उत्तरों के अलावा, आप (3 कम वर्ण) के let ++nबजाय उपयोग कर सकते हैं n=$((n+1))
मुशीफिल

1
इनमें से कौन से तरीके पोर्टेबल हैं, इसके कुछ संकेत अच्छे होंगे।
फहीम मीठा


3
यदि आप गोले बदलने के लिए तैयार हैं, zshहै repeat 10 do some_command; done
चेपनर

1
@ जॉनहैंडवियर मैंने अभी इसे एक ताजा 18.04 डॉकटर कंटेनर में बैश करने की कोशिश की, मूल सिंटैक्स जैसा कि मेरे प्रश्न में पोस्ट किया गया है, अभी भी काम करता है। हो सकता है कि आप बैश के अलावा कोई शेल चला रहे हों, जैसे / बिन / श, जो वास्तव में पानी का छींटा है, जिस स्थिति में मैं वापस आ जाता हूं sh: 1: [[: not found
bstpierre

जवाबों:


479
for run in {1..10}
do
  command
done

या उन लोगों के लिए एक-लाइनर के रूप में जो आसानी से कॉपी और पेस्ट करना चाहते हैं:

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

19
यदि आपके पास पुनरावृत्तियों के बहुत सारे हैं, तो फॉर्म for (n=0;n<k;n++))बेहतर हो सकता है; मुझे संदेह है {1..k}कि रिक्त स्थान द्वारा अलग किए गए उन सभी पूर्णांकों के साथ एक स्ट्रिंग को उत्प्रेरित किया जाएगा।
जो क्रैबग

@ जोए रॉबर्ट, टिप के लिए धन्यवाद। मैं आमतौर पर N <100 का उपयोग कर रहा हूं ताकि यह अच्छा लगे।
bstpierre

10
@bstpierre: बश विस्तार सीमा बश में सीमा निर्दिष्ट करने के लिए चर (आसानी से) का उपयोग नहीं कर सकती है।
अगली सूचना तक रोक दिया गया।

5
यह सच है। ब्रेस विस्तार gnu.org/software/bash/manual/bashref.html#Brace-Expansion के अनुसार चर विस्तार से पहले किया जाता है , इस प्रकार यह किसी भी चर के मूल्यों को कभी नहीं देखेगा।
जो रॉबर्ट सेप

5
चर विस्तार के बारे में दुख की बात है। मैं एन-लूप के बाद का उपयोग कर रहा हूं और संख्याएँ तैयार कर रहा हूं: n=15;for i in $(seq -f "%02g" ${n});do echo $i; done 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
user1830432

203

एक स्थिरांक का उपयोग करना:

for ((n=0;n<10;n++)); do some_command; done

एक चर का उपयोग करना (गणित के भावों को शामिल कर सकते हैं):

x=10; for ((n=0; n < (x / 2); n++)); do some_command; done

4
यह प्रोग्रामिंग भाषा का निकटतम तरीका है ^ ^ - स्वीकार किया जाना चाहिए!
नाम जी वीयू

यह एक बेहतर है क्योंकि यह एक एकल पंक्ति है और इसलिए टर्मिनल के भीतर उपयोग करना आसान है
कुनोक

तुम भी एक चर का उपयोग कर सकते हैं, जैसेx=10 for ((n=0; n < $x; n++));
Jelphy

@ कुनोक यह एक पंक्ति में स्वीकृत उत्तर को चलाने के लिए उतना ही स्वीकार्य है:for run in {1..10}; do echo "on run $run"; done
डगलस एडम्स

क्या होगा यदि nपहले से ही एक विशिष्ट मूल्य पर सेट किया गया है? for (( ; n<10; n++ ))does not काम / संपादन: सबसे अच्छा शायद जैसे अन्य जवाब में से किसी एक का उपयोग while (( n++...एक
phil294

121

इसे हैक करने का एक और सरल तरीका:

seq 20 | xargs -Iz echo "Hi there"

20 बार इको चलाएं।


सूचना है कि seq 20 | xargs -Iz echo "Hi there z"उत्पादन होगा:

हाय वहाँ 1
हाय वहाँ 2
...


4
आपको 1 की भी आवश्यकता नहीं है (बस चला सकते हैं seq 20)
ओलेग वास्केविच

16
संस्करण 2015:seq 20 | xargs -I{} echo "Hi there {}"
मित्नक

4
ध्यान दें कि zयह एक अच्छा प्लेसहोल्डर नहीं है क्योंकि यह इतना सामान्य है कि कमांड टेक्स्ट में एक नियमित पाठ हो सकता है। उपयोग {}बेहतर होगा।
मित्नक

4
नंबर को त्यागने का कोई तरीका seq? तो यह सिर्फ Hi there 20 बार (कोई संख्या) प्रिंट होगा ? संपादित करें: बस का उपयोग करें -I{}और फिर {}कमांड में कोई भी नहीं है
माइक ग्राफ

1
बस कुछ का उपयोग करें, आपको यकीन है कि यह आउटपुट में नहीं होगा, उदाहरण के लिए IIIIIतो यह उदाहरण के लिए अच्छा लगता है:seq 20 | xargs -IIIIII timeout 10 yourCommandThatHangs
rubo77

79

यदि आप zsh शेल का उपयोग कर रहे हैं:

repeat 10 { echo 'Hello' }

जहां 10 बार कमांड की संख्या दोहराई जाएगी।


11
हालांकि यह प्रश्न का उत्तर नहीं है (क्योंकि यह स्पष्ट रूप से बैश का उल्लेख करता है), यह बहुत उपयोगी है और इससे मुझे अपनी समस्या को हल करने में मदद मिली। +1
आउटऑफबाउंड

2
इसके अलावा, अगर आप इसे टर्मिनल में टाइप करते हैं, तो आप कुछ का उपयोग कर सकते हैंrepeat 10 { !! }
Renato गोम्स

28

GNU समानांतर का उपयोग करके आप कर सकते हैं:

parallel some_command ::: {1..1000}

यदि आप संख्या को तर्क के रूप में नहीं चाहते हैं और केवल एक समय में एक ही काम चलाते हैं:

parallel -j1 -N0 some_command ::: {1..1000}

त्वरित परिचय के लिए इंट्रो वीडियो देखें : https://www.youtube.com/playlist?list=PL284C9FF2488BC6V1

ट्यूटोरियल के माध्यम से चलना ( http://www.gnu.org/software/parallel/parallel_tutorial.html )। आप इसके लिए आपको प्यार से आज्ञा दें।


क्यों आप एक उपकरण है जिसका कारण अस्तित्व के लिए, के रूप में स्पष्टतः इसके नाम से साबित प्रयोग करेंगे, चीजों को चलाने के लिए है समानांतर में , और फिर इसे गुप्त argments दे -j1 -N0कि समानांतरवाद बंद बारी ????
रॉस प्रेसर

@RossPresser यह एक बहुत ही उचित सवाल है। इसका कारण यह है कि GNU समानांतर सिंटैक्स का उपयोग करके आप जो करना चाहते हैं उसे व्यक्त करना आसान हो सकता है। सोचिए: आप some_commandबिना किसी तर्क के धारावाहिक में 1000 बार कैसे चलेंगे ? और: क्या आप उससे कम व्यक्त कर सकते हैं parallel -j1 -N0 some_command ::: {1..1000}?
ओले तांगे

ठीक है, मुझे लगता है कि आपके पास एक बिंदु की तरह है, लेकिन यह अभी भी वास्तव में महसूस करता है कि हथौड़ा के रूप में बारीक रूप से तैयार किए गए इंजन ब्लॉक का उपयोग कर रहा है। अगर मैं पर्याप्त रूप से प्रेरित था, और अपने भविष्य के उत्तराधिकारियों के बारे में सोचा कि मैं क्या कर रहा हूं, तो मैं शायद एक शेल स्क्रिप्ट में भ्रम को लपेटूंगा और बस इसे बुलाऊंगा repeat.sh repeatcount some_command। शेल स्क्रिप्ट में कार्यान्वयन के लिए parallel, मैं उपयोग कर सकता हूं , अगर यह पहले से ही मशीन पर स्थापित था (शायद नहीं होगा)। या मैं xargs की ओर गुरुत्वाकर्षण कर सकता हूं क्योंकि यह तब सबसे तेज़ लगता है जब किसी पुनर्निर्देशन की आवश्यकता नहीं होती है some_command
रोस प्रेसर

मैं माफी माँगता हूँ अगर मेरे "बहुत ही उचित प्रश्न" अनुचित तरीके से व्यक्त किया गया था।
रॉस प्रेसर

1
इस विशिष्ट मामले में यह बहुत स्पष्ट नहीं हो सकता है। यह अधिक स्पष्ट हो जाता है यदि आप GNU समानांतर के अधिक विकल्पों का उपयोग करते हैं, उदाहरण के लिए यदि आप 4 बार विफल आदेशों को फिर से प्राप्त करना चाहते हैं और आउटपुट को विभिन्न फाइलों में सहेजना चाहते हैं:parallel -N0 -j1 --retries 4 --results outputdir/ some_command
Ole Tange

18

बैश कॉन्फिग फ़ाइल ( ~/.bashrcअक्सर) में एक साधारण फ़ंक्शन अच्छी तरह से काम कर सकता है।

function runx() {
  for ((n=0;n<$1;n++))
    do ${*:2}
  done
}

इसे इस तरह बुलाओ।

$ runx 3 echo 'Hello world'
Hello world
Hello world
Hello world

1
पसंद है। अब अगर इसे ctrl + c के साथ रद्द किया जा सकता है, तो यह बहुत अच्छा होगा
slashdottir

$ RANDOM n समय को प्रतिध्वनित करने के लिए इस तरीके का उपयोग करने से समान संख्या क्यों प्रदर्शित होती है?
ब्लेडमाइट

3
यह पूरी तरह से काम करता है। केवल एक चीज जिसे मुझे बदलने की ज़रूरत थी, वह यह करने के बजाय कि do ${*:2}मैंने do eval ${*:2}यह सुनिश्चित करने के लिए eval जोड़ा कि यह कमांड चलाने के लिए काम करेगा, जो कि निष्पादनयोग्य के साथ शुरू नहीं होता है। उदाहरण के लिए, यदि आप एक कमांड चलाने से पहले एक पर्यावरण चर सेट करना चाहते हैं जैसे SOME_ENV=test echo 'test'
5_nd_5

12

xargsहै तेजी से :

#!/usr/bin/bash
echo "while loop:"
n=0; time while (( n++ < 10000 )); do /usr/bin/true ; done

echo -e "\nfor loop:"
time for ((n=0;n<10000;n++)); do /usr/bin/true ; done

echo -e "\nseq,xargs:"
time seq 10000 | xargs -I{} -P1 -n1 /usr/bin/true

echo -e "\nyes,xargs:"
time yes x | head -n10000 |  xargs -I{} -P1 -n1 /usr/bin/true

echo -e "\nparallel:"
time parallel --will-cite -j1 -N0 /usr/bin/true ::: {1..10000}

आधुनिक 64-बिट लिनक्स पर, देता है:

while loop:

real    0m2.282s
user    0m0.177s
sys     0m0.413s

for loop:

real    0m2.559s
user    0m0.393s
sys     0m0.500s

seq,xargs:

real    0m1.728s
user    0m0.013s
sys     0m0.217s

yes,xargs:

real    0m1.723s
user    0m0.013s
sys     0m0.223s

parallel:

real    0m26.271s
user    0m4.943s
sys     0m3.533s

यह समझ में आता है, क्योंकि xargsकमांड एक एकल देशी प्रक्रिया है जो /usr/bin/trueकमांड को कई बार जगाती है , इसके बजाय forऔर whileलूप जो सभी बैश में व्याख्या की जाती है। बेशक यह केवल एक ही आदेश के लिए काम करता है; यदि आपको प्रत्येक पुनरावृत्ति लूप में कई कमांड करने की आवश्यकता है, तो यह sh -c 'command1; command2; ...'xargs से गुजरने की तुलना में बस तेज, या शायद तेज़ होगा

-P1यह भी करने के लिए, कहते हैं बदला जा सकता है, -P8समानांतर में 8 प्रक्रियाओं अंडे देने के लिए गति में एक और बड़ा बढ़ावा मिलता है।

मुझे नहीं पता कि GNU समानांतर इतना धीमा क्यों है। मैंने सोचा होगा कि यह xargs के बराबर होगा।


1
GNU पैरेलल काफी सेटअप और बहीखाता पद्धति करता है: यह प्रोग्रामेबल रिप्लेसमेंट स्ट्रिंग्स का समर्थन करता है, यह बफ़र्स आउटपुट करता है, इसलिए दो समानांतर नौकरियों से आउटपुट कभी भी मिश्रित नहीं होता है, यह दिशा का समर्थन करता है (आप ऐसा नहीं कर सकते: xargs "इको> फू") और चूंकि यह नहीं है बैश में लिखा गया है कि इसे पुनर्निर्देशन करने के लिए एक नया खोल देना होगा। प्राथमिक कारण, हालांकि, पर्ल मॉड्यूल IPC :: open3 में है - इसलिए उस तेज़ को प्राप्त करने पर किसी भी कार्य का परिणाम तेजी से GNU समानांतर होगा।
ओले तांगे


7

एक के लिए, आप इसे एक फंक्शन में लपेट सकते हैं:

function manytimes {
    n=0
    times=$1
    shift
    while [[ $n -lt $times ]]; do
        $@
        n=$((n+1))
    done
}

इसे कॉल करें जैसे:

$ manytimes 3 echo "test" | tr 'e' 'E'
tEst
tEst
tEst

2
यह काम नहीं करेगा यदि चलाने के लिए कमांड एक सरल कमांड की तुलना में अधिक जटिल है जिसमें कोई पुनर्निर्देशन नहीं है।
शेपनर

आप इसे अधिक जटिल मामलों के लिए काम कर सकते हैं, लेकिन आपको किसी फ़ंक्शन या स्क्रिप्ट में कमांड को लपेटना पड़ सकता है।
21

2
trयहाँ भ्रामक है और यह के उत्पादन पर काम कर रहा हैmanytimes , नहीं echo। मुझे लगता है कि आपको इसे नमूने से हटा देना चाहिए।
दिमित्री गिंजबर्ग

7

xargs और seq मदद करेगा

function __run_times { seq 1 $1| { shift; xargs -i -- "$@"; } }

दृश्य:

abon@abon:~$ __run_times 3  echo hello world
hello world
hello world
hello world

2
शिफ्ट और कमांड में डबल-डैश क्या करता है? क्या 'शिफ्ट' वास्तव में आवश्यक है?
राज्य बिजली बोर्डों

2
यह काम नहीं करेगा यदि कमांड एक सरल कमांड की तुलना में अधिक जटिल है जिसमें कोई पुनर्निर्देशन नहीं है।
चेपनर

बहुत धीमी, प्रतिध्वनि $ RANDOM 50 बार 7 सेकंड ली गई, और यहां तक ​​कि यह प्रत्येक रैंडम संख्या को समान रूप से प्रदर्शित करता है ...
BladeMight


5

यदि आप इसे समय-समय पर ठीक कर रहे हैं, तो आप इसे प्रत्येक 1 सेकंड अनिश्चित काल के लिए चलाने के लिए निम्न आदेश चला सकते हैं। आप इसे दूसरी बार चलाने के लिए अन्य कस्टम चेक लगा सकते हैं।

watch -n 1 some_command

यदि आप परिवर्तनों की दृश्य पुष्टि करना चाहते हैं, --differencesतो lsकमांड से पहले जोड़ें ।

OSX मैन पेज के अनुसार, वहाँ भी है

- संचयी विकल्प "चिपचिपा" को उजागर करता है, जो कभी भी बदले गए सभी पदों के चल रहे प्रदर्शन को प्रस्तुत करता है। -T या --no-title विकल्प डिस्प्ले के शीर्ष पर अंतराल, कमांड और वर्तमान समय दिखाते हुए हेडर को बंद कर देता है, साथ ही साथ निम्न ब्लैंक लाइन भी।

लिनक्स / यूनिक्स मैन पेज यहां पाया जा सकता है


5

मैंने इस लूप से हल किया, जहां दोहराना एक पूर्णांक है जो छोरों की संख्या का प्रतिनिधित्व करता है

repeat=10
for n in $(seq $repeat); 
    do
        command1
        command2
    done

4

अभी तक एक और जवाब: खाली मापदंडों पर पैरामीटर विस्तार का उपयोग करें:

# calls curl 4 times 
curl -s -w "\n" -X GET "http:{,,,}//www.google.com"

Centos 7 और MacOS पर परीक्षण किया गया।


यह दिलचस्प है, क्या आप इस बारे में कुछ और जानकारी प्रदान कर सकते हैं कि यह क्यों काम करता है?
हसन महमूद

1
यह पैरामीटर विस्तार n बार चल रहा है, लेकिन चूंकि पैरामीटर खाली है, यह वास्तव में जो चलाया जाता है उसे नहीं बदलता है
jcollum

पैरामीटर विस्तार और कर्ल के लिए खोज करने से कोई परिणाम नहीं हुआ है। मैं मुश्किल से कर्ल जानता हूं। यह बहुत अच्छा होगा यदि आप मुझे इस लेख के लिए कुछ लेख या शायद एक और सामान्य नाम बता सकें। धन्यवाद।
हसन महमूद

1
मुझे लगता है कि यह gnu.org/software/bash/manual/html_node/…
jcollum

3

सभी मौजूदा उत्तर की आवश्यकता होती है bash, और मानक BSD UNIX /bin/sh(जैसे, kshOpenBSD पर ) के साथ काम नहीं करते हैं ।

नीचे दिए गए कोड को किसी भी BSD पर काम करना चाहिए:

$ echo {1..4}
{1..4}
$ seq 4
sh: seq: not found
$ for i in $(jot 4); do echo e$i; done
e1
e2
e3
e4
$

2

थोड़ा सा भोला लेकिन यह वही है जो मुझे आमतौर पर अपने सिर के ऊपर से याद आता है:

for i in 1 2 3; do
  some commands
done

@ Joe-koberg के उत्तर के समान। विशेष रूप से अगर आपको कई पुनरावृत्तियों की आवश्यकता है, तो बेहतर है, मेरे लिए अन्य वाक्यविन्यास को याद रखना मुश्किल है क्योंकि पिछले वर्षों में मैं bashबहुत अधिक उपयोग नहीं कर रहा हूं । मेरा मतलब है कि स्क्रिप्टिंग के लिए कम से कम।


1

स्क्रिप्ट फ़ाइल

bash-3.2$ cat test.sh 
#!/bin/bash

echo "The argument is  arg: $1"

for ((n=0;n<$1;n++));
do
  echo "Hi"
done

और नीचे उत्पादन

bash-3.2$  ./test.sh 3
The argument is  arg: 3
Hi
Hi
Hi
bash-3.2$


0

छोरों के लिए शायद यह करने का सही तरीका है, लेकिन यहां एक मजेदार विकल्प है:

echo -e {1..10}"\n" |xargs -n1 some_command

यदि आपको अपने मंगलाचरण के लिए पैरामीटर के रूप में पुनरावृति संख्या की आवश्यकता है, तो उपयोग करें:

echo -e {1..10}"\n" |xargs -I@ echo now I am running iteration @

संपादित करें: यह सही टिप्पणी की गई थी कि ऊपर दिए गए समाधान केवल सरल कमांड रन (कोई पाइप आदि) के साथ आसानी से काम करेंगे। आप हमेशा एक का उपयोग कर सकते हैंsh -c अधिक जटिल सामान करने के लिए , लेकिन इसके लायक नहीं।

एक अन्य विधि जिसका मैं आमतौर पर उपयोग करता हूं वह निम्नलिखित फ़ंक्शन है:

rep() { s=$1;shift;e=$1;shift; for x in `seq $s $e`; do c=${@//@/$x};sh -c "$c"; done;}

अब आप इसे इस रूप में कह सकते हैं:

rep 3 10 echo iteration @

पहले दो नंबर रेंज देते हैं। @यात्रा संख्या में अनुवाद किया जाएगा। अब आप इसका उपयोग पाइपों के साथ भी कर सकते हैं:

rep 1 10 "ls R@/|wc -l"

आप निर्देशिका R1 .. R10 में फ़ाइलों की संख्या दे।


1
यह काम नहीं करेगा यदि कमांड एक सरल कमांड की तुलना में अधिक जटिल है जिसमें कोई पुनर्निर्देशन नहीं है।
14

काफी उचित है, लेकिन ऊपर मेरा संपादन देखें। संपादित विधि एक sh -c का उपयोग करती है, इसलिए पुनर्निर्देशन के साथ भी काम करना चाहिए।
स्टेक्सिया

rep 1 2 touch "foo @"दो फ़ाइल "फू 1" और "फू 2" नहीं बनाएंगे; बल्कि यह तीन फाइलें "फू", "1" और "2" बनाता है। हो सकता है कि उद्धरण का सही उपयोग करने का एक तरीका हो printfऔर %q, लेकिन शब्दों का एक मनमाना अनुक्रम प्राप्त करने के लिए यह मुश्किल हो सकता है कि पास करने के लिए एक स्ट्रिंग में सही ढंग से उद्धृत किया जाए sh -c
चेपनर

ओपी ने और अधिक संक्षिप्त करने के लिए कहा , तो आप ऐसा कुछ क्यों जोड़ रहे हैं, जब पहले से ही 5 और संक्षिप्त उत्तर हैं?
ज़ोस्का

एक बार जब आप repअपनी परिभाषा को परिभाषित करते हैं .bashrc, तो आगे के चालान बहुत अधिक संक्षिप्त हो जाते हैं।
मुशीफिल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.