Bash에서 문자열 배열을 반복합니까?


1500

15 문자열을 반복하는 스크립트를 작성하고 싶습니다 (배열 가능합니까?) 가능합니까?

다음과 같은 것 :

for databaseName in listOfNames
then
  # Do something
end

답변:


2388

다음과 같이 사용할 수 있습니다.

## declare an array variable
declare -a arr=("element1" "element2" "element3")

## now loop through the above array
for i in "${arr[@]}"
do
   echo "$i"
   # or do whatever with individual element of the array
done

# You can access them using echo "${arr[0]}", "${arr[1]}" also

여러 줄 배열 선언에도 작동

declare -a arr=("element1" 
                "element2" "element3"
                "element4"
                )

775

물론 가능합니다.

for databaseName in a b c d e f; do
  # do something like: echo $databaseName
done 

자세한 내용은 while 및 until Bash Loops를 참조 하십시오.


18
이 방법의 문제점은 무엇입니까? 간단한 경우에는 작동하는 것으로 보이며 @anubhava의 대답보다 직관적입니다.
— 박사 Jan-Philip Gehrcke

17
이것은 예를 들어 명령 대체와 함께 특히 잘 작동합니다 for year in $(seq 2000 2013).
— Brad Koch

22
문제는 배열을 반복하는 것에 대한 질문이었습니다.
— mgalgs

20
'선언'접근 방식은 동일한 배열을 여러 곳에서 반복해야하는 경우에 가장 효과적입니다. 이 방법은 더 깨끗하지만 유연성이 떨어집니다.
— StampyCode

15
왜 이것이 # 1이 아닌가? 깔끔하고 문자열을 설정하는 것만으로 쉽게 배열을 재사용 할 수 있습니다 DATABASES="a b c d e f".
— Nerdmaster

201

그 대답 중 어느 것도 카운터를 포함하지 않습니다 ...

#!/bin/bash
## declare an array variable
declare -a array=("one" "two" "three")

# get length of an array
arraylength=${#array[@]}

# use for loop to read all values and indexes
for (( i=1; i<${arraylength}+1; i++ ));
do
  echo $i " / " ${arraylength} " : " ${array[$i-1]}
done

산출:

1  /  3  :  one
2  /  3  :  two
3  /  3  :  three

7
이것은 대답이 받아 들여 져야합니다. 배열 요소에 공백이있을 때 작동하는 유일한 방법입니다.
— jesjimher

1
이것은 카운터가있는 예제 출력을 위해서만입니다. 그것을 바꾸는 것은 아주 사소한 일이며 똑같이 작동합니다.
— caktux

7
끝의 에코는 버그입니다. 상수를 인용 할 필요가 없으며 확장을 인용하거나 다음과 같이 안전하게 인용 할 수 있습니다 echo "$i / ${arraylength} : ${array[$i-1]}".-그렇지 않으면 $iglob가 포함되어 있으면 확장되고 탭이 포함되어 있으면 다음과 같이 변경됩니다. 공간 등
— Charles Duffy

10
@bzeaman, 물론-그런 것들에 대해 조잡하다면 무언가를 증명하기 위해 상황 분석 (방금 전과 같이)이 필요하며 컨텍스트가 변경되거나 코드가 다른 장소에서 재사용 될 경우 다시 분석해야합니다. 다른 이유가 있더라도 예기치 않은 제어 흐름이 가능합니다. 강력한 방식으로 작성하고 상황에 관계없이 정확합니다.
— Charles Duffy

5
희소 배열, 즉 배열에 요소가없는 경우에는 작동하지 않습니다. 예를 들어 배열 요소 A [1] = 'xx', A [4] = 'yy'및 A [9] = 'zz'가 있으면 길이는 3이되고 루프는 모든 요소를 ​​처리하지 않습니다. .
— Mr Ed

144

예

for Item in Item1 Item2 Item3 Item4 ;
  do
    echo $Item
  done

산출:

Item1
Item2
Item3
Item4

공백을 보존하기 위해; 작은 따옴표 또는 큰 따옴표 목록 항목 및 큰 따옴표 목록 확장.

for Item in 'Item 1' 'Item 2' 'Item 3' 'Item 4' ;
  do
    echo "$Item"
  done

산출:

Item 1
Item 2
Item 3
Item 4

여러 줄에 걸쳐 목록을 만들려면

for Item in Item1 \
            Item2 \
            Item3 \
            Item4
  do
    echo $Item
  done

산출:

Item1
Item2
Item3
Item4


단순 목록 변수

List=( Item1 Item2 Item3 )

또는

List=(
      Item1 
      Item2 
      Item3
     )

목록 변수를 표시하십시오.

echo ${List[*]}

산출:

Item1 Item2 Item3

목록을 반복합니다 :

for Item in ${List[*]} 
  do
    echo $Item 
  done

산출:

Item1
Item2
Item3

목록을 살펴볼 함수를 작성하십시오.

Loop(){
  for item in ${*} ; 
    do 
      echo ${item} 
    done
}
Loop ${List[*]}

선언 키워드 (명령)를 사용하여 기술적으로 배열이라고하는 목록을 만듭니다.

declare -a List=(
                 "element 1" 
                 "element 2" 
                 "element 3"
                )
for entry in "${List[@]}"
   do
     echo "$entry"
   done

산출:

element 1
element 2
element 3

연관 배열 만들기 사전 :

declare -A continent

continent[Vietnam]=Asia
continent[France]=Europe
continent[Argentina]=America

for item in "${!continent[@]}"; 
  do
    printf "$item is in ${continent[$item]} \n"
  done

산출:

 Argentina is in America
 Vietnam is in Asia
 France is in Europe

CVS 변수 또는 파일을 목록에 추가합니다 .
공간에서 내부 필드 구분 기호를 원하는대로 변경
아래 예에서 쉼표로 변경되었습니다

List="Item 1,Item 2,Item 3"
Backup_of_internal_field_separator=$IFS
IFS=,
for item in $List; 
  do
    echo $item
  done
IFS=$Backup_of_internal_field_separator

산출:

Item 1
Item 2
Item 3

번호를 매길 필요가있는 경우 :

` 

이것을 백틱이라고합니다. 명령을 백틱 안에 넣습니다.

`commend` 

키보드의 숫자 옆이나 탭 키 위에 있습니다. 표준 미국 영어 키보드.

List=()
Start_count=0
Step_count=0.1
Stop_count=1
for Item in `seq $Start_count $Step_count $Stop_count`
    do 
       List+=(Item_$Item)
    done
for Item in ${List[*]}
    do 
        echo $Item
    done

출력은 다음과 같습니다

Item_0.0
Item_0.1
Item_0.2
Item_0.3
Item_0.4
Item_0.5
Item_0.6
Item_0.7
Item_0.8
Item_0.9
Item_1.0

bash 동작에 더 익숙해지기 :

파일로리스트 만들기

cat <<EOF> List_entries.txt
Item1
Item 2 
'Item 3'
"Item 4"
Item 7 : *
"Item 6 : * "
"Item 6 : *"
Item 8 : $PWD
'Item 8 : $PWD'
"Item 9 : $PWD"
EOF

목록 파일을 목록으로 읽고 표시

List=$(cat List_entries.txt)
echo $List
echo '$List'
echo "$List"
echo ${List[*]}
echo '${List[*]}'
echo "${List[*]}"
echo ${List[@]}
echo '${List[@]}'
echo "${List[@]}"

BASH 명령 줄 참조 매뉴얼 : 특정 문자 나 단어를 쉘에 대한 특별한 의미.


7
이것은 잘못입니다. 요구가되게합니다 "${List[@]}", 올바른 것으로 따옴표와 함께 . ${List[@]}잘못되었습니다. ${List[*]}잘못되었습니다. 시도하십시오 List=( "* first item *" "* second item *" )-에 대한 올바른 동작을 얻을 수 for item in "${List[@]}"; do echo "$item"; done있지만 다른 변형은 아닙니다.
— Charles Duffy

그렇습니다. 특수 문자가 해석되기 때문에 바람직하거나 바람직하지 않을 수 있습니다. 포함하도록 답변을 업데이트했습니다.
— FireInTheSky

2
나는 여전히 더 정확하고 견고한 접근법을 먼저 제시 할 것을 강력히 제안한다 . 사람들은 종종 효과가있는 것처럼 보이는 첫 번째 답변을받습니다. 그 대답에 숨겨진 경고가있는 경우 나중에 노출 될 수 있습니다. (; 그냥 인용의 부족에 의해 파괴되는 와일드 카드 아닙니다 List=( "first item" "second item" )으로 구분한다 first, item, second, item뿐만 아니라).
— Charles Duffy

또한 구문 분석에 사람들을 이끌 수있는 예제의 사용을 피하는 고려해 볼 수 있습니다 ls, 출력 모범 사례의 위반을 .
— Charles Duffy

1
당신은 내가 한 적이없는 주장을 반박하고 있습니다. 나는 떠들썩한 파티의 인용 의미를 꽤 잘 알고 - 볼 stackoverflow.com/tags/bash/topusers
— 찰스 더피

108

4ndrew의 답변과 같은 정신으로 :

listOfNames="RA
RB
R C
RD"

# To allow for other whitespace in the string:
# 1. add double quotes around the list variable, or
# 2. see the IFS note (under 'Side Notes')

for databaseName in "$listOfNames"   #  <-- Note: Added "" quotes.
do
  echo "$databaseName"  # (i.e. do action / processing of $databaseName here...)
done

# Outputs
# RA
# RB
# R C
# RD

B. 이름에 공백이 없습니다.

listOfNames="RA
RB
R C
RD"

for databaseName in $listOfNames  # Note: No quotes
do
  echo "$databaseName"  # (i.e. do action / processing of $databaseName here...)
done

# Outputs
# RA
# RB
# R
# C
# RD

노트

  1. 두 번째 예에서 using listOfNames="RA RB R C RD"은 동일한 출력을가집니다.

데이터를 가져 오는 다른 방법은 다음과 같습니다.

stdin에서 읽기

# line delimited (each databaseName is stored on a line)
while read databaseName
do
  echo "$databaseName"  # i.e. do action / processing of $databaseName here...
done # <<< or_another_input_method_here
  1. bash IFS "필드 구분선"[ 1 ] 구분 기호는 스크립트에서 다른 공백을 허용하도록 지정할 수 있습니다 (예 IFS='\n': 또는 MacOS IFS='\r').
  2. 나는 또한 받아 들인 대답을 좋아한다 :)-나는이 발췌 문장을 질문에 대답하는 다른 유용한 방법으로 포함시켰다.
  3. #!/bin/bash스크립트 파일의 맨 위에 포함 은 실행 환경을 나타냅니다.
  4. 이것을 간단하게 코딩하는 방법을 알아내는 데 몇 달이 걸렸습니다. :)

다른 소스 ( while read loop )


이렇게하면 eol이 문자열 구분 기호로 사용되므로 문자열 내에 공백이 허용됩니다. 그러나 공백이있는 문자열은 하위 문자열로 분리되어 매우 나쁩니다. 나는이 답변 stackoverflow.com/a/23561892/1083704 가 더 낫다고 생각합니다 .
— Val

1
@Val,에 대한 참조로 코드 주석을 추가했습니다 IFS. 모든 사람에게 IFS특정 구분 기호를 지정하면 하위 문자열로 구분되지 않고 다른 공백을 문자열에 포함시킬 수 있습니다.
— user2533809

7
이것은 나를 위해 작동하지 않습니다. $databaseName전체 목록 만 포함하므로 단일 반복 만 수행합니다.
— AlikElzin-kilaka

@ AlikElzin-kilaka 아래의 대답은이 문제를 해결하여 문자열이 모든 줄에 대해 루프가 실행되도록합니다.
— Jamie

42

다음 구문을 사용할 수 있습니다 ${arrayName[@]}

#!/bin/bash
# declare an array called files, that contains 3 values
files=( "/etc/passwd" "/etc/group" "/etc/hosts" )
for i in "${files[@]}"
do
    echo "$i"
done

31

아무도 이것을 게시하지 않았다는 것에 놀랐습니다. 배열을 반복하는 동안 요소의 인덱스가 필요한 경우 다음을 수행 할 수 있습니다.

arr=(foo bar baz)

for i in ${!arr[@]}
do
    echo $i "${arr[i]}"
done

산출:

0 foo
1 bar
2 baz

나는 이것이 "전통적인"for-loop 스타일 ( for (( i=0; i<${#arr[@]}; i++ ))) 보다 훨씬 더 우아하다는 것을 안다 .

( ${!arr[@]}그리고 $i일부는 어쨌든 말을 인용 제안,하지만 그건 그냥 개인적인 취향입니다 때문에 그들이있는 거 단지 숫자를 인용 할 필요가 없습니다.)


2
이것은 실제로 선택된 답변이어야합니다. 1 : 간단하고 읽기 쉽습니다. 2 : 공백을 올바르게 처리하고 IFS 넌센스가 방해받지 않습니다. 3 : 희소 배열을 올바르게 처리합니다.
— mrm

20

이것은 또한 읽기 쉽다 :

FilePath=(
    "/tmp/path1/"    #FilePath[0]
    "/tmp/path2/"    #FilePath[1]
)

#Loop
for Path in "${FilePath[@]}"
do
    echo "$Path"
done

4
이것은 FilePath 배열 정의 전에 IFS 변수를 올바르게 설정 한 경우에만 명확하고 나에게 적합합니다 (FilePath 배열 요소의 공백 및 변수 대체 포함) IFS=$'\n' .이 시나리오의 다른 솔루션에서도 작동 할 수 있습니다.
— Alan Forsyth

8

스크립트 또는 함수에 대한 암시 적 배열 :

anubhava 의 정답 외에도 : 루프의 기본 구문이 다음과 같은 경우 :

for var in "${arr[@]}" ;do ...$var... ;done

이 특별한 경우는:

스크립트 또는 함수를 실행할 때 명령 행에 전달 된 인수 는 $@배열 변수에 지정 되며 $1,, $2등으로 액세스 할 수 있습니다 $3.

이것은 다음을 통해 (테스트를 위해) 채울 수 있습니다

set -- arg1 arg2 arg3 ...

이 배열에 대한 루프 는 다음과 같이 간단하게 작성할 수 있습니다.

for item ;do
    echo "This is item: $item."
  done

참고 예약 된 작업을하는 것이 in존재하지없이 배열 이름도!

견본:

set -- arg1 arg2 arg3 ...
for item ;do
    echo "This is item: $item."
  done
This is item: arg1.
This is item: arg2.
This is item: arg3.
This is item: ....

이것은 다음과 같습니다

for item in "$@";do
    echo "This is item: $item."
  done

그런 다음 스크립트로 :

#!/bin/bash

for item ;do
    printf "Doing something with '%s'.\n" "$item"
  done

스크립트에서이 내용을 저장 myscript.sh, chmod +x myscript.sh다음,

./myscript.sh arg1 arg2 arg3 ...
Doing something with 'arg1'.
Doing something with 'arg2'.
Doing something with 'arg3'.
Doing something with '...'.

함수 에서 동일 :

myfunc() { for item;do cat <<<"Working about '$item'."; done ; }

그때

myfunc item1 tiem2 time3
Working about 'item1'.
Working about 'tiem2'.
Working about 'time3'.

7
listOfNames="db_one db_two db_three"
for databaseName in $listOfNames
do
  echo $databaseName
done

아니면 그냥

for databaseName in db_one db_two db_three
do
  echo $databaseName
done

7

간단한 방법 :

arr=("sharlock"  "bomkesh"  "feluda" )  ##declare array

len=${#arr[*]}  # it returns the array length

#iterate with while loop
i=0
while [ $i -lt $len ]
do
    echo ${arr[$i]}
    i=$((i+1))
done


#iterate with for loop
for i in $arr
do
  echo $i
done

#iterate with splice
 echo ${arr[@]:0:3}

6

Korn 쉘에서는 선언 배열이 작동하지 않습니다. Korn 쉘에 아래 예제를 사용하십시오.

promote_sla_chk_lst="cdi xlob"

set -A promote_arry $promote_sla_chk_lst

for i in ${promote_arry[*]};
    do
            echo $i
    done

2
편집기에서 코드 하이 라이터를 사용하여 코드를보기 좋게 만드십시오.
— 비둘기

5
알아두면 좋지만이 질문은 배쉬에 관한 것입니다.
— Brad Koch

1
로트 사 버그. 공백이있는 목록 항목을 사용할 수없고, 글로브 문자가있는 목록 항목을 가질 수 없습니다. for i in ${foo[*]}기본적으로 항상 잘못된 것입니다- for i in "${foo[@]}"원래 목록의 경계를 유지하고 glob 확장을 방지하는 형식입니다. 그리고 반향이 필요합니다echo "$i"
— Charles Duffy

4

이것은 user2533809의 답변과 비슷하지만 각 파일은 별도의 명령으로 실행됩니다.

#!/bin/bash
names="RA
RB
R C
RD"

while read -r line; do
    echo line: "$line"
done <<< "$names"

3

Korn 쉘을 사용중인 경우 " set -A databaseName "이 있고 그렇지 않으면 " 선언 -a databaseName "이 있습니다.

모든 쉘에서 작동하는 스크립트를 작성하려면

 set -A databaseName=("db1" "db2" ....) ||
        declare -a databaseName=("db1" "db2" ....)
# now loop 
for dbname in "${arr[@]}"
do
   echo "$dbname"  # or whatever

done

모든 껍질에서 작동해야합니다.


3
아니, 그렇지 않습니다 : $ bash --versionGNU bash는 버전 4.3.33 (0) -release (AMD64-portbld-freebsd10.0) $ set -A databaseName=("db1" "db2" ....) || declare -a databaseName=("db1" "db2" ....)배쉬 : 근처에 구문 오류가 예기치 않은 토큰 '('
— 버니 라이터

2

이 시도. 작동하고 테스트되었습니다.

for k in "${array[@]}"
do
    echo $k
done

# For accessing with the echo command: echo ${array[0]}, ${array[1]}

3
실제로 제대로 작동하지 않습니다. 시도 array=( "hello world" )하거나 arrray=( "*" ); 첫 번째 경우에는 별도로 인쇄 hello되고 world두 번째 경우에는*
— Charles Duffy

6
... 쉘에서 "테스트 된"것을 호출하기 전에 공백과 globs가 모두있는 코너 케이스를 확인하십시오.
— 찰스 더피

2

모든 Bash 스크립트 / 세션의 첫 번째 줄 :

say() { for line in "${@}" ; do printf "%s\n" "${line}" ; done ; }

사용 예 :

$ aa=( 7 -4 -e ) ; say "${aa[@]}"
7
-4
-e

고려할 수 있습니다 : 여기서 옵션으로 echo해석-e


2

단일 회선 루핑,

 declare -a listOfNames=('db_a' 'db_b' 'db_c')
 for databaseName in ${listOfNames[@]}; do echo $databaseName; done;

다음과 같은 결과가 나옵니다.

db_a
db_b
db_c

2

내가 실제로 필요한 것은 다음과 같습니다.

for i in $(the_array); do something; done

예를 들어 :

for i in $(ps -aux | grep vlc  | awk '{ print $2 }'); do kill -9 $i; done

(이름에 vlc가있는 모든 프로세스를 죽일 것입니다)


1

git pull업데이트를 위해 프로젝트 배열을 반복합니다 .

#!/bin/sh
projects="
web
ios
android
"
for project in $projects do
    cd  $HOME/develop/$project && git pull
end

7
이 코드 스 니펫은 문제를 해결할 수 있지만 설명을 포함하면 게시물의 품질을 향상시키는 데 실제로 도움이됩니다. 앞으로 독자들에게 질문에 대한 답변을 제공하므로 해당 사람들이 코드 제안의 이유를 모를 수도 있습니다. 설명 주석으로 코드를 복잡하게 만들지 마십시오. 이렇게하면 코드와 설명의 가독성이 떨어집니다!
— kayess
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.