하나의 루프에서 두 개의 시퀀스를 통해 실행


8

아래처럼 쉘에서 동일한 루프에서 두 개의 시퀀스를 실행하려고합니다.

#!/bin/bash
for i in (1..15) and (20..25) ;
do
     echo $i
     ......
     .....other process
done

어떻게 이것을 달성 할 수 있습니까?


@zanna-첫 번째 생각은 부울 "and"는 배타적이며 결과는 두 세트 모두에 존재하는 숫자라는 것을 의미합니다. 이 경우에는 없습니다. 포괄적 인 "and"가 있습니까?
— ravery

1
@ravery 내가 찾는 것을 설명하기 위해 "and"를 넣었습니다
— HISI

2
@YassineSihi-글쎄요. 말을하는 언어에는 "and"가 포함되지만 논리적 인 "and"는 대부분의 프로그래밍 언어에 배타적이기 때문에 많은 새로운 프로그래머들이 두뇌를 재교육 할 수있을 때까지이 시점에서 우연히 발견됩니다.
— ravery

답변:


10

이를 위해 중괄호 확장 만 필요합니다.

$ for n in {1..3} {200..203}; do echo $n; done
1
2
3
200
201
202
203

for( )에 목록을 전달할 수 있습니다 .for i in x y z; do stuff "$i"; done

따라서 여기서 중괄호 { }는 쉘이 시퀀스를 목록으로 확장하도록합니다. 쉘은 인수 목록을 분할하기 때문에 공백을 둘 필요가 있습니다.


그렇습니다. . . 그리고 당신은 심지어 ^ _0에 대한 루프 필요가 없습니다
— 세르지 Kolodyazhnyy

@SergiyKolodyazhnyy 나는 그들이 실제로 echo숫자를 원하지 않는다고 생각 합니다
— Zanna

예, touch파일 과 같은 일종의 작업을 원한다면 touch {1..15}.txt {20..25}.txt여기에서 루프가 필요하지 않습니다. 그러나 물론 동일한 수의 여러 작업 인 경우 루프를 사용할 수 있습니다.
— Sergiy Kolodyazhnyy

6

또는 우리는 seq( 일련의 숫자 인쇄) 를 사용할 수 있습니다 .

for i in `seq 1 3` `seq 101 103`; do echo $i; done
for i in $(seq 1 3) $(seq 101 103); do echo $i; done

반복적 인 작업을위한 스크립트 인 경우 함수를 사용할 수 있습니다.

#!/bin/bash
my_function() { echo "$1"; }
for i in {1..3}; do my_function "$i"; done
for i in {101..103}; do my_function "$i"; done
#!/bin/bash
my_function() { for i in `seq $1 $2`; do echo "$i"; done; }
my_function "1" "3"
my_function "101" "103"

4

Zanna의 대답 과 pa4080의 대답 은 모두 좋으며 대부분의 상황에서 그중 하나와 함께 갈 것입니다. 아마도 말할 필요도 없지만 완전성을 위해 어쨌든 말할 것입니다. 각 값을 배열에로드 한 다음 배열을 반복 할 수 있습니다. 예를 들면 다음과 같습니다.

the_array=( 1 2 3 4 5 6 7 8 9 10 20 21 22 23 24 25 )
for i in "${the_array[@]}";
do
    echo $i
done

@ SergiyKolodyazhnyy : 피드백 감사합니다. 나는 그것이 내가 배운 방식 인만큼 나이가 들었고, 보통 쉘 스크립트를 작성하는 경우는 거의 없습니다. 그러나 배열을 사용하도록 답변을 업데이트했습니다.
— GreenMatt

아주 잘 ! 행복한 스크립팅!
— Sergiy Kolodyazhnyy

3

루프없이 루핑

Zanna의 대답은 절대적으로 정확하고 bash에 적합하지만 루프를 사용하지 않고도 더 향상시킬 수 있습니다.

printf "%d\n"  {1..15} {20..25}

의 행동 printf의 수는 경우에하도록이다 ARGUMENTS에서 형식 컨트롤보다 큰 'FORMAT STRING'다음, printf모든 분할합니다 ARGUMENTS 동일한 조각으로하고 때까지 반복해서 형식 문자열에 끼워 보관이 부족 ARGUMENTS목록입니다.

이식성을 위해 노력하고 있다면 printf "%d\n" $(seq 1 15) $(seq 20 25)대신 활용할 수 있습니다

이것을 더 재미있게 보자. 단순히 숫자를 인쇄하는 것이 아니라 행동을 원한다고 가정 해 봅시다. 일련의 숫자 중에서 파일을 만들기 위해 쉽게 할 수 있습니다 touch {1..15}.txt {20..25}.txt. 여러 가지 일이 발생하면 어떻게해야합니까? 우리는 또한 다음과 같이 할 수 있습니다 :

$ printf "%d\n" {1..15} {20..25} | xargs -I % bash -c 'touch "$1.txt"; stat "$1.txt"' sh %

또는 우리가 그것을 오래된 학교 스타일로 만들고 싶다면 :

printf "%d\n" {1..15} {20..25} | while read -r line; do 
    touch "$line".txt;
    stat "$line".txt;
    rm "$line".txt; 
done

휴대용이지만 자세한 대안

중괄호 확장이없는 쉘 (이것이 {1..15} {20..25}의존 하는 쉘)에서 작동하는 스크립트 솔루션을 만들고 싶다면 간단한 while 루프를 작성할 수 있습니다.

#!/bin/sh
start=$1
jump=$2
new_start=$3
end=$4

i=$start
while [ $i -le $jump ]
do
    printf "%d\n" "$i"
    i=$((i+1))
    if [ $i -eq $jump ] && ! [ $i -eq $end ];then
        printf "%d\n" "$i"
        i=$new_start
        jump=$end
    fi
done

물론이 솔루션은 더 장황하고 일부는 단축 될 수 있지만 작동합니다. 테스트 ksh, dash, mksh, 물론 bash.


배쉬 C 스타일 루프

그러나 우리가 루프 배쉬 특정 (어떤 이유로 든 인쇄뿐만 아니라 그 숫자로 무언가를하는)을 만들고 싶다면 이것을 할 수도 있습니다 (기본적으로 휴대용 솔루션의 C 루프 버전).

last=15; for (( i=1; i<=last;i++ )); do printf "%d\n" "$i"; [[ $i -eq $last ]] && !  [[ $i -eq 25 ]] && { i=19;last=25;} ;done

또는 더 읽기 쉬운 형식으로 :

last=15
for (( i=1; i<=last;i++ )); 
do 
    printf "%d\n" "$i"
    [[ $i -eq $last ]] && !  [[ $i -eq 25 ]] && { i=19;last=25;} 
done

다른 루핑 접근법의 성능 비교

bash-4.3$ time bash -c 'printf "%d\n" {0..50000}>/dev/null'

real    0m0.196s
user    0m0.124s
sys 0m0.028s
bash-4.3$ time bash -c 'for i in {1..50000}; do echo $i > /dev/null; done'

real    0m1.819s
user    0m1.328s
sys 0m0.476s
bash-4.3$ time bash -c ' i=0;while [ $i -le 50000 ]; do echo $i>/dev/null; i=$((i+1)); done'

real    0m3.069s
user    0m2.544s
sys 0m0.500s
bash-4.3$ time bash -c 'for i in $(seq 1 50000); do printf "%d\n" > /dev/null; done'

real    0m1.879s
user    0m1.344s
sys 0m0.520s

비쉘 대안

우리가 여기 파이썬 솔루션이 될 수 있기 때문에

$ python3 -c 'print("\n".join([str(i) for i in (*range(1,16),*range(20,26))]))'

또는 약간의 껍질로 :

bash-4.3$ python3 << EOF
> for i in (*range(16),*range(20,26)):
>    print(i)
> EOF

1
방금 테스트했습니다 touch $(printf "%d\n" {1..15} {20..25}):-)
— pa4080

1
@ pa4080 사실에 대한 bash당신도 필요하지 않은 $()단지가 touch {1..15}.txt {20..25}.txt :) 그러나 물론 우리가 사용할 수 printf "%d\n{1..15} {20..25}`와 xargs우리가보다 더 많은 일을하기를 원한다면 touch파일. 작업을 수행하는 방법은 여러 가지가 있으며 스크립팅을 너무 재미있게 만듭니다!
— Sergiy Kolodyazhnyy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.