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


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.