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)).
musiphil

1
이러한 방법 중 어느 것이 이식 가능한지에 대한 몇 가지 징후는 좋을 것입니다.
Faheem Mitha


3
당신이 쉘을 변경하고자하는 경우, zsh이 있습니다 repeat 10 do some_command; done.
chepner

1
@ JohnVandivier 방금 신선한 18.04 도커 컨테이너의 bash에서 시도했지만 내 질문에 게시 된 원래 구문은 여전히 ​​작동합니다. 어쩌면 / bin / sh와 같은 bash 이외의 쉘을 실행 중일 수 있습니다.이 경우 실제로 대시가 발생 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}공백으로 구분 된 모든 정수로 문자열을 구체화 할 것으로 생각 됩니다.
Joe Koberg

@Joe Koberg, 팁 주셔서 감사합니다. 나는 일반적으로 N <100을 사용하므로 이것이 좋아 보입니다.
bstpierre

10
@bstpierre : 중괄호 확장 양식은 변수를 사용하여 Bash의 범위를 쉽게 지정할 수 없습니다.
추후 공지가있을 때까지 일시 중지되었습니다.

5
사실입니다. gnu.org/software/bash/manual/bashref.html#Brace-Expansion 에 따라 변수 확장 전에 브레이스 확장이 수행 되므로 변수 값이 표시되지 않습니다.
Joe Koberg

5
변수 확장에 대한 슬픈 점. 나는 다음을 사용하여 n 번 반복하고 숫자를 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
형식화했습니다

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
이것은 프로그래밍 언어에 가장 가까운 방법입니다 ^^-받아 들여 져야합니다!
Nam G VU

이것은 한
줄이기

다음과 같은 변수를 사용할 수도 있습니다.x=10 for ((n=0; n < $x; n++));
Jelphy

@Kunok 한 줄에 허용 된 답변을 실행하는 것만 큼 허용됩니다.for run in {1..10}; do echo "on run $run"; done
Douglas Adams

n이미 특정 값으로 설정되어 있으면 어떻게 합니까? for (( ; n<10; n++ ))나던 작업 / 편집 : 최고의 아마 등 다른 답변 중 하나를 사용 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)
Oleg Vaskevich

16
버전 2015 :seq 20 | xargs -I{} echo "Hi there {}"
mitnk

4
참고 z이 명령 텍스트에서 일반 텍스트가 될 수 있도록 공통이기 때문에 좋은 자리가 아닙니다. 사용 {}이 더 좋습니다.
mitnk

4
에서 숫자를 버리는 방법은 seq무엇입니까? 그래서 Hi there 20 번 인쇄합니다 (숫자 없음)? 편집 : 그냥 사용 -I{}하고 {}명령에 아무것도 없습니다
Mike Graf

1
그냥 무언가를 사용하면 출력에 없을 것이라고 확신합니다. 예를 들어 IIIII다음과 같습니다.seq 20 | xargs -IIIIII timeout 10 yourCommandThatHangs
rubo77

79

zsh 쉘을 사용중인 경우 :

repeat 10 { echo 'Hello' }

여기서 10은 명령이 반복되는 횟수입니다.


11
그것은 bash에 대해 명시 적으로 언급했기 때문에 질문에 대한 대답은 아니지만 매우 유용하며 문제를 해결하는 데 도움이되었습니다. +1
OutOfBound

2
또한 터미널에 방금 입력 한 경우 다음과 같이 사용할 수 있습니다.repeat 10 { !! }
Renato Gomes

28

GNU Parallel을 사용하면 다음을 수행 할 수 있습니다.

parallel some_command ::: {1..1000}

숫자를 인수로 원하지 않고 한 번에 하나의 작업 만 실행하려는 경우 :

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

빠른 소개를 위해 소개 동영상을 시청하십시오. https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

학습서 ( http://www.gnu.org/software/parallel/parallel_tutorial.html )를 진행하십시오. 당신은 그것을 사랑하는 명령 줄입니다.


그 이름으로 명백히 입증 된 것처럼 존재의 이유가 무엇인가를 병렬 로 실행 한 다음 병렬 처리를 해제하는 비밀스러운 주장을 -j1 -N0하는 이유 는 무엇 입니까?
Ross Presser

@RossPresser 매우 합리적인 질문입니다. 그 이유는 GNU Parallel 구문을 사용하여 원하는 것을 표현하는 것이 더 쉬울 수 있기 때문입니다. 생각하십시오 : 어떻게 some_command인수없이 1000 회 연속으로 실행 하시겠습니까? 그리고 :보다 짧게 표현할 수 있습니까 parallel -j1 -N0 some_command ::: {1..1000}?
올레 탱

글쎄, 당신이 일종의 요점을 가지고 있다고 생각하지만, 여전히 정교하게 만들어진 엔진 블록을 망치로 사용하는 것처럼 느껴집니다. 내가 충분히 동기 부여 된 경우 내가 무슨 짓을했는지 이해하려고 내 미래의 후계자 배려를 느꼈다, 나는 아마 쉘 스크립트에 혼란을 포장하고 단지와 전화 것입니다 repeat.sh repeatcount some_command. 쉘 스크립트에서 구현 parallel하기 위해 이미 컴퓨터에 설치되어있는 경우 사용할 수 있습니다 (아마도 아닐 것입니다). 또는 xargs로 끌릴 수도 있습니다 some_command. 리디렉션이 필요하지 않은 경우 가장 빠릅니다 .
Ross Presser

"매우 합리적인 질문"이 부당한 방식으로 표현 된 경우 사과드립니다.
Ross Presser

1
이 특정 경우에는 그렇게 명확하지 않을 수 있습니다. 더 많은 GNU Parallel 옵션을 사용하면 더욱 분명해집니다. 예를 들어 실패한 명령을 4 번 다시 시도하고 출력을 다른 파일에 저장하려는 경우 :parallel -N0 -j1 --retries 4 --results outputdir/ some_command
Ole Tange

18

bash 구성 파일의 간단한 기능은 ~/.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 번 에코하는 이유는 무엇입니까?
BladeMight

3
이것은 완벽하게 작동합니다. 내가 변경해야 할 유일한 것은 실행 파일로 시작하지 않는 명령을 실행하기 위해 do ${*:2}eval 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 비트 Linux에서 다음을 제공합니다.

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명령이 Bash에서 모두 해석되는 and 루프 /usr/bin/true대신 명령을 여러 번 생성하는 단일 기본 프로세스이므로 의미가 있습니다. 물론 이것은 하나의 명령에서만 작동합니다. 각 반복에서 여러 명령을 수행 해야하는 경우 루프는 xargs에 전달 하는 것보다 빠르거나 빠릅니다.forwhilesh -c 'command1; command2; ...'

-P1또한 말에 변경 될 수 있습니다 -P8속도에서 또 다른 큰 후원을 얻기 위해 병렬로 8 개 프로세스를 생성 할 수 있습니다.

GNU 병렬이 왜 그렇게 느린 지 모르겠습니다. 나는 그것이 xargs와 비교 될 것이라고 생각했을 것입니다.


1
GNU Parallel은 많은 설정과 부기 기능을 제공합니다. 프로그램 가능한 대체 문자열을 지원하고, 출력을 버퍼링하여 두 개의 병렬 작업의 출력이 혼합되지 않으며, 방향을 지원합니다 (xargs "echo> foo"). bash로 작성하면 리디렉션을 수행하기 위해 새로운 쉘을 생성해야합니다. 그러나 가장 큰 원인은 Perl 모듈 IPC :: open3에 있습니다. 따라서 더 빨리 작업하면 GNU Parallel이 더 빨라집니다.
Ole Tange


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
실행할 명령이 경로 재 지정이없는 간단한 명령보다 복잡한 경우에는 작동하지 않습니다.
chepner

더 복잡한 경우에는 작동시킬 수 있지만 명령을 함수 나 스크립트로 래핑해야 할 수도 있습니다.
bta

2
tr여기에는 오해의 소지가되고, 그것은의 출력에 일하고 manytimes,하지 echo. 샘플에서 제거해야한다고 생각합니다.
Dmitry Ginzburg

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
명령에서 시프트와 이중 대시는 무엇을합니까? '시프트'가 정말로 필요한가?
sebs

2
명령이 리디렉션이없는 간단한 명령보다 복잡한 경우에는 작동하지 않습니다.
chepner

매우 느리고 에코 $ RANDOM 50 배가 7 초 걸렸지 만, 매번 같은 난수를 표시합니다 ...
BladeMight


5

정기적으로 수행해도 괜찮다면 다음 명령을 실행하여 1 초마다 무기한으로 실행할 수 있습니다. 다른 사용자 지정 검사를 제자리에 배치하여 n 번 실행할 수 있습니다.

watch -n 1 some_command

변경 사항을 시각적으로 확인 --differences하려면 ls명령 전에 추가 하십시오 .

OSX 매뉴얼 페이지에 따르면

--cumulative 옵션은 강조 표시를 "고정"하여 변경 한 모든 위치를 계속 표시합니다. -t 또는 --no-title 옵션은 디스플레이 맨 위에 간격, 명령 및 현재 시간과 다음 빈 줄을 표시하는 헤더를 끕니다.

Linux / Unix 매뉴얼 페이지는 여기 에서 찾을 수 있습니다


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에서 테스트되었습니다.


이것은 흥미 롭습니다. 왜 이것이 작동하는지에 대해 더 자세히 설명해 주시겠습니까?
Hassan Mahmud

1
그것은 매개 변수 확장 n 번을 실행하지만 매개 변수이기 때문에 실제로 실행되는 것을 변경되지 않습니다 비어
jcollum

매개 변수 확장 및 컬을 검색해도 결과가 없습니다. 나는 컬을 거의 알지 못한다. 이 기능에 대한 기사 또는 다른 일반적인 이름을 알려 주시면 좋을 것입니다. 감사.
Hassan Mahmud


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

For 루프는 아마도 올바른 방법 일 것입니다. 그러나 여기에 재미있는 대안이 있습니다 :

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
명령이 리디렉션이없는 간단한 명령보다 복잡한 경우에는 작동하지 않습니다.
chepner

충분히 공평하지만 위의 편집 내용을 참조하십시오. 편집 된 방법은 sh -c를 사용하므로 리디렉션에서도 작동해야합니다.
stacksia

rep 1 2 touch "foo @""foo 1"과 "foo 2"라는 두 파일을 만들지 않습니다. 오히려 "foo", "1"및 "2"라는 세 개의 파일을 만듭니다. printfand를 사용하여 %q인용 부호를 올바르게 얻는 방법이있을 수 있지만 임의의 단어 시퀀스를 단일 문자열로 올바르게 인용하여 전달하는 것은 까다로울 것 sh -c입니다.
chepner

OP는 더 간결한 질문을 했으므로 이미 5 개의 간결한 답변이있을 때 왜 이와 같은 내용을 추가하고 있습니까?
zoska

당신의 정의 정의되면 rep당신의를 .bashrc더 호출은 훨씬 더 간결하게된다.
musiphil
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.