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.