Bash에서 배열의 요소를 어떻게 결합 할 수 있습니까?


416

Bash에 이와 같은 배열이있는 경우 :

FOO=( a b c )

요소를 쉼표로 어떻게 결합합니까? 예를 들어을 생성 a,b,c합니다.

답변:


571

Pascal Pilz의 솔루션을 100 % 순수 Bash의 함수로 다시 작성 (외부 명령 없음) :

function join_by { local IFS="$1"; shift; echo "$*"; }

예를 들어

join_by , a "b c" d #a,b c,d
join_by / var local tmp #var/local/tmp
join_by , "${FOO[@]}" #a,b,c

또는 @gniourf_gniourf의 아이디어를 사용하여 printf를 사용하여 다중 문자 구분 기호를 지원할 수 있습니다

function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }

예를 들어

join_by , a b c #a,b,c
join_by ' , ' a b c #a , b , c
join_by ')|(' a b c #a)|(b)|(c
join_by ' %s ' a b c #a %s b %s c
join_by $'\n' a b c #a<newline>b<newline>c
join_by - a b c #a-b-c
join_by '\' a b c #a\b\c

9
다중 문자 구분 기호에 이것을 사용하십시오. function join {perl -e '$ s = shift @ARGV; 인쇄 조인 ($ s, @ARGV); ' "$ @"; } ','abc # a, b, c 가입
— Daniel Patru

4
어쨌든 @dpatru는 순수한 bash를 만들기 위해?
— CMCDragonkai

4
@puchu 작동하지 않는 것은 다중 문자 구분 기호입니다. "공간이 작동하지 않는다"고 말하면 공간과의 결합이 작동하지 않는 것처럼 들립니다. 그렇습니다.
— Eric

6
출력을 변수에 저장하는 경우 서브 쉘 생성을 촉진합니다. konsolebox스타일 사용 :) function join { local IFS=$1; __="${*:2}"; }또는 function join { IFS=$1 eval '__="${*:2}"'; }. 그런 다음 사용하십시오 __. 예, 나는 __결과 변수로 사용을 장려하는 사람입니다 .) (그리고 일반적인 반복 변수 또는 임시 변수). 컨셉이 인기있는 Bash 위키 사이트에 도착하면 나를 복사했습니다 :)
— konsolebox

6
$d의 형식 지정자에 확장 을 넣지 마십시오 printf. 당신은 당신이 "탈출"때문에 당신은 이제 안전 생각 %하지만, 다른주의 사항이 있습니다 : 구분 기호가 백 슬래시 (예를 들어, 포함 된 경우 \n) 또는 때 하이픈 (그리고 내가 지금 생각할 수 없다, 아마 다른 사람)과의 구분이 시작됩니다. 물론이를 고칠 수 있습니다 (백 슬래시를 이중 백 슬래시로 대체하고 사용하십시오 printf -- "$d%s"). 그러나 어느 시점에서 쉘을 사용하는 대신 쉘과 싸우고 있다고 느낄 수 있습니다. 그렇기 때문에 아래 답변에서 가입 조건에 구분 기호를 추가했습니다.
— gniourf_gniourf

206

또 다른 해결책 :

#!/bin/bash
foo=('foo bar' 'foo baz' 'bar baz')
bar=$(printf ",%s" "${foo[@]}")
bar=${bar:1}

echo $bar

편집 : 동일하지만 다중 문자 가변 길이 구분 기호의 경우 :

#!/bin/bash
separator=")|(" # e.g. constructing regex, pray it does not contain %s
foo=('foo bar' 'foo baz' 'bar baz')
regex="$( printf "${separator}%s" "${foo[@]}" )"
regex="${regex:${#separator}}" # remove leading separator
echo "${regex}"
# Prints: foo bar)|(foo baz)|(bar baz

7
+1. 무엇에 대해 printf -v bar ",%s" "${foo[@]}". fork(실제로 clone) 하나 적습니다 . 파일을 읽는 것도 잊어 버립니다 printf -v bar ",%s" $(<infile).
— TrueY

14
기도에 $separator포함되어 있지 않거나 그 대신에 %s당신은 다음과 같이 printf강하게 할 수 있습니다 printf "%s%s" "$separator" "${foo[@]}".
— musiphil

5
@musiphil 잘못되었습니다. bash man : "포맷은 모든 인수를 소비하는 데 필요에 따라 재사용됩니다. printf "%s%s"첫 번째 경우에만 출력 에서 두 개의 형식 플레이스 홀더를 사용하면 구분 기호를 사용한 다음 나머지 인수를 연결합니다.
— AnyDev

3
@AndrDevEK : 실수를 잡아 주셔서 감사합니다. 대신 나는 다음과 같은 것을 제안 할 것이다 printf "%s" "${foo[@]/#/$separator}".
— musiphil

2
@musiphil, 감사합니다. 예! 그런 다음 printf가 중복되고 해당 줄을로 줄일 수 있습니다 IFS=; regex="${foo[*]/#/$separator}". 이 시점에서 이것은 본질적으로 IMO가 처음부터 더 깨끗하다는, 즉 IFS 변경 범위와 임시 변수의 범위를 제한하는 기능을 사용하여 gniourf_gniourf의 대답이됩니다.
— AnyDev

145
$ foo=(a "b c" d)
$ bar=$(IFS=, ; echo "${foo[*]}")
$ echo "$bar"
a,b c,d

3
콜론 주위의 큰 따옴표와 큰 따옴표는 필요하지 않습니다. 단지 내부 따옴표가 필요합니다 :bar=$( IFS=, ; echo "${foo[*]}" )
— ceving

8
루프가 필요없고 외부 명령이 필요하지 않고 인수의 문자 세트에 추가 제한을 부과하지 않는 가장 컴팩트 한 솔루션의 경우 +1입니다.
— sep

22
나는 해결책을 좋아하지만, IFS가 하나의 문자 인 경우에만 작동합니다
— Jayen

8
@에서 *와 같이 대신 대신 사용하면 이것이 작동하지 않는 이유 는 $(IFS=, ; echo "${foo[@]}")무엇입니까? 나는 *이미 요소에 공백을 보존하고 있음을 알 수 있습니다 . 왜냐하면 @일반적 으로이 술에 필요하기 때문 입니다.
— haridsv

10
위의 질문에 대한 답을 찾았습니다. 이에 대한 답은 IFS가에만 인정된다는 것입니다 *. bash 맨 페이지에서 "특수 매개 변수"를 검색하고 다음 옆에있는 설명을 찾으십시오 *.
— haridsv

66

예를 들어

SAVE_IFS="$IFS"
IFS=","
FOOJOIN="${FOO[*]}"
IFS="$SAVE_IFS"

echo "$FOOJOIN"

3
그렇게하면 IFS-가 변수라고 생각합니다. 당신은해야 할 echo "-${IFS}-"(중괄호가 변수 이름에서 대시를 분리).
— 추후 공지가있을 때까지 일시 중지되었습니다.

1
여전히 같은 결과를 얻었습니다. (단지 요점을 설명하기 위해 대시를 넣었습니다… echo $IFS같은 일을합니다.
— David Wolever

41
그러나 이것은 여전히 ​​작동하는 것 같습니다. 따라서 Bash의 대부분의 것들과 마찬가지로, 나는 그것을 이해하고 내 인생을 계속하는 것처럼 가장합니다.
— David Wolever

2
"-"는 변수 이름에 유효한 문자가 아니므로 $ IFS-를 사용할 때 쉘이 올바른 작업을 수행하므로 $ {IFS}-(Linux 및 solaris의 bash, ksh, sh 및 zsh)가 필요하지 않습니다. 또한 동의합니다).
— Idelic

2
@David 에코와 Dennis의 차이점은 그가 큰 따옴표를 사용했다는 것입니다. IFS의 내용은 단어 구분 문자의 선언으로 '입력시'사용되므로 항상 따옴표없이 빈 줄을 얻습니다.
— martin clayton

30

놀랍게도 내 솔루션은 아직 제공되지 않았습니다. :) 이것은 가장 간단한 방법입니다. 기능이 필요하지 않습니다.

IFS=, eval 'joined="${foo[*]}"'

참고 :이 솔루션은 비 POSIX 모드에서 잘 작동하는 것으로 관찰되었습니다. 에서 POSIX 모드 , 요소는 여전히 제대로 결합되지만, IFS=,영구적된다.


불행히도 단일 문자 구분자에 대해서만 작동
— maoizm

24

다음은 작업을 수행하는 100 % 순수 Bash 함수입니다.

join() {
    # $1 is return variable name
    # $2 is sep
    # $3... are the elements to join
    local retname=$1 sep=$2 ret=$3
    shift 3 || shift $(($#))
    printf -v "$retname" "%s" "$ret${@/#/$sep}"
}

보기:

$ a=( one two "three three" four five )
$ join joineda " and " "${a[@]}"
$ echo "$joineda"
one and two and three three and four and five
$ join joinedb randomsep "only one element"
$ echo "$joinedb"
only one element
$ join joinedc randomsep
$ echo "$joinedc"

$ a=( $' stuff with\nnewlines\n' $'and trailing newlines\n\n' )
$ join joineda $'a sep with\nnewlines\n' "${a[@]}"
$ echo "$joineda"
 stuff with
newlines
a sep with
newlines
and trailing newlines


$

이것은 후행 줄 바꿈도 유지하며 함수의 결과를 얻기 위해 서브 쉘이 필요하지 않습니다. printf -v(왜 원하지 않습니까?)가 마음에 들지 않고 변수 이름을 전달하면 반환 된 문자열에 전역 변수를 사용할 수 있습니다.

join() {
    # $1 is sep
    # $2... are the elements to join
    # return is in global variable join_ret
    local sep=$1 IFS=
    join_ret=$2
    shift 2 || shift $(($#))
    join_ret+="${*/#/$sep}"
}

1
마지막 해결책은 매우 좋지만 join_ret지역 변수를 만든 다음 끝에 에코하여 깨끗하게 만들 수 있습니다 . 이렇게하면 join ()을 일반적인 쉘 스크립팅 방식으로 사용할 수 있으며 $(join ":" one two three)전역 변수가 필요하지 않습니다.
— James Sneeringer

1
@JamesSneeringer 서브 쉘을 피하기 위해 의도적으로이 디자인을 사용했습니다. 쉘 스크립팅에서는 다른 많은 언어와 달리 전역 변수가 그렇게 나쁜 것은 아닙니다. 특히 그들이 서브 쉘을 피하기 위해 여기에 있다면. 또한 $(...)후행 줄 바꿈을 제거합니다. 따라서 배열의 마지막 필드에 후행 줄 바꿈이 포함되어 있으면 줄 바꿈됩니다 (내 디자인으로 트리밍되지 않은 데모 참조).
— gniourf_gniourf

이 ^ _ ^ 나를 행복하게하는, 멀티 문자 구분와 함께 작동
— spiffytech

"printf -v를 원하지 않는 이유는 무엇입니까?"를 해결하려면 : Bash에서 로컬 변수는 실제로 함수 로컬이 아니므로 이와 같은 작업을 수행 할 수 있습니다. (로컬 변수 x를 사용하여 함수 f1을 호출하면 x를 수정하는 함수 f2가 호출됩니다. x는 f1의 범위 내에서 로컬로 선언됩니다) 그러나 실제로 로컬 변수가 작동하는 방식은 아닙니다. 로컬 변수가 실제로 로컬 인 경우 (또는 예를 들어 bash 및 ksh에서 모두 작동해야하는 스크립트에서 가정되는 경우)이 "전체 이름에 변수를 저장하여 값을 반환"스키마 전체에 문제가 발생합니다.
— tetsujin

15

이것은 기존 솔루션과 크게 다르지 않지만 별도의 기능을 사용하지 않고 IFS부모 셸에서 수정하지 않으며 모두 한 줄에 있습니다.

arr=(a b c)
printf '%s\n' "$(IFS=,; printf '%s' "${arr[*]}")"

~를 야기하는

a,b,c

제한 : 구분 기호는 한 문자를 초과 할 수 없습니다.


13

외부 명령을 사용하지 않는 경우 :

$ FOO=( a b c )     # initialize the array
$ BAR=${FOO[@]}     # create a space delimited string from array
$ BAZ=${BAR// /,}   # use parameter expansion to substitute spaces with comma
$ echo $BAZ
a,b,c

경고, 요소에는 공백이 없다고 가정합니다.


4
중간 변수를 사용하지 않으려면 더 짧게 수행 할 수 있습니다.echo ${FOO[@]} | tr ' ' ','
— jesjimher

2
나는 부정적인 투표를 이해하지 못한다. 여기에 게시 된 다른 것보다 훨씬 작고 읽기 쉬운 솔루션이며 공간이있을 때 작동하지 않는다는 것을 분명히 경고합니다.
— jesjimher

12

배열을 문자열로 반향 한 다음 공백을 줄 바꿈으로 변환 한 다음 paste모든 줄을 한 줄로 결합 하는 데 사용 합니다.

tr " " "\n" <<< "$FOO" | paste -sd , -

결과 :

a,b,c

이것은 나에게 가장 빠르고 가장 깨끗한 것 같습니다!


$FOO그러나 배열의 첫 번째 요소입니다. 또한 공백이 포함 된 배열 요소도 중단됩니다.
— Benjamin W.

9

@ doesn 's 's solution을 재사용하면 $ {: 1}의 정의와 중개 변수의 필요성을 피함으로써 하나의 진술만으로도 가능합니다.

echo $(printf "%s," "${LIST[@]}" | cut -d "," -f 1-${#LIST[@]} )

printf는 '포맷 문자열은 인수를 만족시키기 위해 필요한만큼 자주 재사용됩니다.' 문자열의 연결이 문서화되도록 매뉴얼 페이지에 있습니다. 그런 다음 LIST 길이를 사용하여 마지막 스퍼터를 자르는 것이 좋습니다. 컷은 필드 수로 LIST의 길이 만 유지하기 때문입니다.


7
s=$(IFS=, eval 'echo "${FOO[*]}"')

8
당신은 당신의 답을 살육시켜야합니다.
— joce

가장 좋은 것. 감사!!
— peter pan gz

4
이 답변이 보안 허점을 열어 요소의 공간을 파괴하기 때문에이 답변을 다운 투표 할 수 있기를 바랍니다.
— eel ghEEz

1
실제로 @bxm은 공백을 유지하는 것으로 보이며 반향 인수 컨텍스트에서 벗어날 수 없습니다. 내가 생각하는 추가 @Q그들에 목공이있을 때 잘못 해석에서 결합 된 값을 벗어날 수 : foo=("a ," "b ' ' c" "' 'd e" "f " ";" "ls -latr"); s=$(IFS=, eval 'echo "${foo[*]@Q}"'); echo "${s}"출력'a ,','b '\'' '\'' c',''\'' '\''d e','f ',';','ls -latr '
— 장어 ghEEz

1
필요한 경우가 아니면 서브 쉘을 사용하는 솔루션을 피하십시오.
— konsolebox

5

모든 길이의 구분 기호를 허용하는 printf 솔루션 (@ doesn 's는 중요하지 않습니다)

#/!bin/bash
foo=('foo bar' 'foo baz' 'bar baz')

sep=',' # can be of any length
bar=$(printf "${sep}%s" "${foo[@]}")
bar=${bar:${#sep}}

echo $bar

선행 쉼표로 출력을 생성합니다.
— Mark Renouf

마지막 bar = $ {bar : $ {# sep}}은 구분 기호를 제거합니다. 방금 bash 쉘에 복사하여 붙여 넣었으며 작동합니다. 어떤 쉘을 사용하고 있습니까?
— 리카르도 갈리

2
모든 printf 형식 지정자 (예 : %s실수로 $sep문제가 발생할 수 있음)
— Peter.O

sep로 소독 할 수 있습니다 ${sep//\%/%%}. 나는 귀하의 솔루션을 ${bar#${sep}}또는 ${bar%${sep}}(대체) 보다 낫습니다 . 결과를와 같은 일반 변수로 저장하는 함수로 변환하면 __좋지 않습니다 echo.
— konsolebox

function join_by { printf -v __ "${1//\%/%%}%s" "${@:2}"; __=${__:${#1}}; }
— konsolebox

4
$ set a 'b c' d

$ history -p "$@" | paste -sd,
a,b c,d

맨 위에 있어야합니다.
— Eric Walker

6
이것은 정상에 있어서는 안됩니다. 만약 그렇다면 HISTSIZE=0?
— har-wradim 12

@ har-wradim, 요령은 paste -sd, 역사의 사용에 것이 아닙니다.
— Veda

@ Veda 아니요, 조합 사용에 관한 것이므로 HISTSIZE=0시도해보십시오.
— har-wradim

4

최고 답변의 짧은 버전 :

joinStrings() { local a=("${@:3}"); printf "%s" "$2${a[@]/#/$1}"; }

용법:

joinStrings "$myDelimiter" "${myArray[@]}"

1
더 긴 버전이지만 배열 변수에 대한 인수 조각의 사본을 만들 필요는 없습니다.join_strings () { local d="$1"; echo -n "$2"; shift 2 && printf '%s' "${@/#/$d}"; }
— Rockallite

또 다른 버전 : join_strings () { local d="$1"; echo -n "$2"; shift 2 && printf '$d%s' "${@}"; } 이것은 사용법과 함께 작동 join_strings 'delim' "${array[@]}"하거나 인용되지 않은 :join_strings 'delim' ${array[@]}
— Cometsong

4

다음 아이디어와 함께 지금까지 모든 세계의 최고를 결합하십시오.

# join with separator
join_ws()  { local IFS=; local s="${*/#/$1}"; echo "${s#"$1$1$1"}"; }

이 작은 걸작은

  • 100 % 순수 bash (일시적으로 설정되지 않은 IFS로 매개 변수 확장, 외부 호출 없음, printf 없음 ...)
  • 작고 완벽하며 완벽한 (단일 및 다중 문자 제한 기, 공백, 줄 바꿈 및 기타 셸 특수 문자가 포함 된 제한 기, 빈 구분 기호 사용)
  • 효율적 (서브 쉘 없음, 배열 복사 없음)
  • 간단하고 어리 석고, 어느 정도는 아름답고 유익한

예 :

$ join_ws , a b c
a,b,c
$ join_ws '' a b c
abc
$ join_ws $'\n' a b c
a
b
c
$ join_ws ' \/ ' A B C
A \/ B \/ C

1
그렇게 좋지는 않습니다 : 적어도 2 가지 문제 : 1. join_ws ,(인수없이) 잘못 출력 ,,합니다. 2. join_ws , -e잘못 출력하지 않습니다. ( echo대신에 잘못 사용하고 있기 때문 printf입니다.) 난 당신의 사용을 광고하는 이유는 실제로 모르는 echo대신을 printf: echo악명 파괴하고, printf강력한 내장입니다.
— gniourf_gniourf 21시 02 분

1

지금 나는 사용하고 있습니다 :

TO_IGNORE=(
    E201 # Whitespace after '('
    E301 # Expected N blank lines, found M
    E303 # Too many blank lines (pep8 gets confused by comments)
)
ARGS="--ignore `echo ${TO_IGNORE[@]} | tr ' ' ','`"

어느 것이 효과가 있지만 배열 요소에 공백이 있으면 (일반적인 경우) 끔찍하게 중단됩니다.

(관심있는 사람들을 위해, 이것은 pep8.py 주위의 래퍼 스크립트입니다 )


그 배열 값은 어디서 얻습니까? 그렇게 하드 코딩하고 있다면 왜 foo = "a, b, c"가 아닌가?
— ghostdog74

이 경우 실제로 하고 값을 하드 코딩,하지만 난 개별적으로 각에 댓글을 달 수 있도록 배열에 넣고 싶습니다. 내가 의미하는 바를 보여주기 위해 답변을 업데이트했습니다.
— David Wolever

실제로 bash를 사용한다고 가정하면 더 잘 작동 할 수 있습니다 ARGS="--ignore $(echo "${TO_IGNORE[@]}" | tr ' ' ',')". 연산자 $()는 백틱보다 강력합니다 ( $()및의 중첩 허용 ""). ${TO_IGNORE[@]}큰 따옴표로 감싸는 것도 도움이됩니다.
— kevinarpe

1

내 시도.

$ array=(one two "three four" five)
$ echo "${array[0]}$(printf " SEP %s" "${array[@]:1}")"
one SEP two SEP three four SEP five

1

여러 문자 구분 기호에 perl을 사용하십시오.

function join {
   perl -e '$s = shift @ARGV; print join($s, @ARGV);' "$@"; 
}

join ', ' a b c # a, b, c

또는 한 줄로 :

perl -le 'print join(shift, @ARGV);' ', ' 1 2 3
1, 2, 3

있지만, 나를 위해 작동 join에 약간의 쓰레기와 이름이 충돌 OS X.. 내가 호출 것 conjoined, 아마, 또는 jackie_joyner_kersee?
— Alex Gray

1

지금까지 최고의 세계 조합에 대한 자세한 의견은 @gniourf_gniourf에게 감사드립니다. 철저하게 설계 및 테스트되지 않은 코드를 게시하여 죄송합니다. 더 나은 시도가 있습니다.

# join with separator
join_ws() { local d=$1 s=$2; shift 2 && printf %s "$s${@/#/$d}"; }

개념에 의한이 아름다움은

  • (아직도) 100 % 순수 bash (printf도 내장되어 있음을 명시 적으로 지적 해 주셔서 감사합니다. 전에는 알지 못했습니다 ...)
  • 다중 문자 분리 문자와 함께 작동
  • 보다 간결하고 완전하며 이번에는 쉘 특수 문자 또는 제어 문자 사용 또는 구분 기호 및 / 또는 매개 변수에 문자 없음 및 엣지 케이스를 포함하여 쉘 스크립트의 임의의 하위 문자열로 신중하고 장기적인 스트레스 테스트를 거쳤습니다. , 코너 케이스 및 인수가 전혀없는 다른 퀴즈. 그렇다고 더 이상 버그가 없다고 보장 할 수는 없지만 버그를 찾기가 조금 더 어려울 것입니다. BTW, 현재 최고 투표 답변과 관련 문제조차도 -e 버그 ...

추가 예 :

$ join_ws '' a b c
abc
$ join_ws ':' {1,7}{A..C}
1A:1B:1C:7A:7B:7C
$ join_ws -e -e
-e
$ join_ws $'\033[F' $'\n\n\n'  1.  2.  3.  $'\n\n\n\n'
3.
2.
1.
$ join_ws $ 
$

1

결합하려는 요소가 공백으로 구분 된 문자열 배열이 아닌 경우 다음과 같이 할 수 있습니다.

foo="aa bb cc dd"
bar=`for i in $foo; do printf ",'%s'" $i; done`
bar=${bar:1}
echo $bar
    'aa','bb','cc','dd'

예를 들어, 유스 케이스는 일부 문자열이 쉘 스크립트로 전달되며 SQL 쿼리에서 실행하려면 이것을 사용해야합니다.

./my_script "aa bb cc dd"

my_script에서 "SELECT * FROM table WHERE name IN ( 'aa', 'bb', 'cc', 'dd')을 수행해야합니다. 그러면 위의 명령이 유용합니다.


printf -v bar ...서브 쉘에서 printf 루프를 실행하고 출력을 캡처하는 대신 사용할 수 있습니다 .
— codeforester

위의 모든 화려한 upvoted 솔루션은 작동하지 않았지만 당신의 원유는 나를 위해했습니다 (Y)
— ishandutta2007

1

다음은 대부분의 POSIX 호환 쉘이 지원하는 것입니다.

join_by() {
    # Usage:  join_by "||" a b c d
    local arg arr=() sep="$1"
    shift
    for arg in "$@"; do
        if [ 0 -lt "${#arr[@]}" ]; then
            arr+=("${sep}")
        fi
        arr+=("${arg}") || break
    done
    printf "%s" "${arr[@]}"
}

Bash 코드는 좋지만 POSIX 에는 배열 (또는 local)이 전혀 없습니다.
— Anders Kaseorg

@Anders : 네 나는 아주 최근이 어려운 방법을 배웠다 :( 대부분의 POSIX 호환 쉘이 배열을 지원하는 것 않기 때문에 비록 내가 지금은 그것을 떠날거야.
— user541686

1

변수 간접 참조를 사용하여 배열을 직접 참조해도 작동합니다. 명명 된 참조도 사용할 수 있지만 4.3에서만 사용할 수있게되었습니다.

이 형식의 함수를 사용하면 구분 기호를 선택적으로 사용할 수 있으며 (기본값 IFS은 공백 의 첫 문자 인 기본값입니다 . 원한다면 빈 문자열로 만들 수도 있습니다) 값을 두 번 확장하지 않습니다 (먼저 매개 변수로 전달 될 때 두 번째로"$@" 함수 내부에서 ).

이 솔루션은 또한 사용자가 다른 변수에 할당 된 문자열의 결합 된 버전을 얻기 위해 서브 쉘을 소환하는 명령 대체 내에서 함수를 호출 할 필요가 없습니다.

function join_by_ref {
    __=
    local __r=$1[@] __s=${2-' '}
    printf -v __ "${__s//\%/%%}%s" "${!__r}"
    __=${__:${#__s}}
}

array=(1 2 3 4)

join_by_ref array
echo "$__" # Prints '1 2 3 4'.

join_by_ref array '%s'
echo "$__" # Prints '1%s2%s3%s4'.

join_by_ref 'invalid*' '%s' # Bash 4.4 shows "invalid*[@]: bad substitution".
echo "$__" # Prints nothing but newline.

보다 편리한 기능 명을 사용하십시오.

이것은 3.1에서 5.0- 알파까지 작동합니다. 관찰 된 바와 같이, 변수 간접은 변수뿐만 아니라 다른 매개 변수와도 작동합니다.

매개 변수는 값을 저장하는 엔티티입니다. 이름, 숫자 또는 특수 매개 변수 아래 아래에 나열된 특수 문자 중 하나 일 수 있습니다. 변수는 이름으로 표시되는 매개 변수입니다.

배열과 배열 요소도 매개 변수 (값을 저장하는 엔티티)이며 배열에 대한 참조는 기술적으로 매개 변수에 대한 참조입니다. 그리고 특별한 매개 변수 @와 array[@]마찬가지로 유효한 참조를 만듭니다.

매개 변수 자체에서 참조를 벗어난 변경되거나 선택적인 확장 형식 (예 : 하위 문자열 확장)이 더 이상 작동하지 않습니다.

최신 정보

Bash 5.0 릴리스 버전에서 변수 간접 지정 은 이미 간접 확장 이라고 하며 그 동작은 매뉴얼에 명시 적으로 문서화되어 있습니다.

매개 변수의 첫 문자가 느낌표 (!)이고 매개 변수가 이름 참조가 아닌 경우 간접적 인 수준을 나타냅니다. Bash는 나머지 매개 변수를 새 매개 변수로 확장하여 형성된 값을 사용합니다. 그런 다음이 값이 확장되고 해당 값은 원래 매개 변수의 확장이 아닌 나머지 확장에 사용됩니다. 이것을 간접 확장이라고합니다.

의 문서에 참고 촬영 ${parameter}, parameter라고 "설명 (단위)로서 쉘 파라미터 PARAMETERS 또는 배열을 참조 ." 그리고 배열 문서에서 "배열의 모든 요소는 ${name[subscript]}"를 사용하여 참조 될 수 있습니다 . 이것은 __r[@]배열 참조를 만듭니다 .

인수 버전으로 결합

Riccardo Galli 's answer 내 의견 을 참조하십시오 .


2
__변수 이름 으로 사용해야하는 특별한 이유가 있습니까? 코드를 실제로 읽을 수 없게 만듭니다.
— PesaThe

@PesaThe 단지 환경 ​​설정입니다. 반환 변수에 일반 이름을 사용하는 것이 좋습니다. 제네릭 이외의 다른 이름은 특정 기능에 속하므로 암기해야합니다. 다른 변수에서 값을 반환하는 여러 함수를 호출하면 코드를 쉽게 따르지 않을 수 있습니다. 일반 이름을 사용하면 스크립터가 충돌을 피하기 위해 반환 변수에서 적절한 변수로 값을 전송하게되며, 반환 된 값의 위치가 명확 해 지므로 코드를 더 읽기 쉽게 만듭니다. 그래도 그 규칙에 대한 예외는 거의 없습니다.
— konsolebox

0

이 방법은 값 내의 공백을 처리하지만 루프가 필요합니다.

#!/bin/bash

FOO=( a b c )
BAR=""

for index in ${!FOO[*]}
do
    BAR="$BAR,${FOO[$index]}"
done
echo ${BAR:1}

0

루프에서 배열을 빌드하는 경우 간단한 방법은 다음과 같습니다.

arr=()
for x in $(some_cmd); do
   arr+=($x,)
done
arr[-1]=${arr[-1]%,}
echo ${arr[*]}

0

x=${"${arr[*]}"// /,}

가장 짧은 방법입니다.

예,

arr=(1 2 3 4 5)
x=${"${arr[*]}"// /,}
echo $x  # output: 1,2,3,4,5

1
공백이있는 문자열에는 제대로 작동하지 않습니다 .`t = (a "b c"d); echo $ {t [2]} ( "b c"로 인쇄); echo $ { "$ {t [*]}"// /,} (인쇄 a, b, c, d)
— kounoupis

7
bash: ${"${arr[*]}"// /,}: bad substitution
— 카메론 허드슨

0

아마도 파티에 늦었을 수도 있지만 이것은 나를 위해 작동합니다.

function joinArray() {
  local delimiter="${1}"
  local output="${2}"
  for param in ${@:3}; do
    output="${output}${delimiter}${param}"
  done

  echo "${output}"
}

-1

아마도 나는 bash / zsh 전체에 익숙하지 않기 때문에 분명한 것을 놓치고 있지만 전혀 사용할 필요가없는 것처럼 보입니다 printf. 그것 없이는 정말 못 생겼습니다.

join() {
  separator=$1
  arr=$*
  arr=${arr:2} # throw away separator and following space
  arr=${arr// /$separator}
}

적어도 지금까지 문제없이 작동했습니다.

예를 들어, join \| *.sh내 ~디렉토리 에 있다고 가정 해 보겠습니다.utilities.sh|play.sh|foobar.sh . 나를 위해 충분합니다.

편집 : 이것은 기본적으로 Nil Geisweiller의 답변 이지만 기능으로 일반화되었습니다.


1
나는 downvoter는 아니지만 함수에서 전역을 조작하는 것은 꽤 별난 것 같습니다.
— tripleee

-2
liststr=""
for item in list
do
    liststr=$item,$liststr
done
LEN=`expr length $liststr`
LEN=`expr $LEN - 1`
liststr=${liststr:0:$LEN}

이것은 끝에 추가 쉼표를 처리합니다. 나는 배쉬 전문가가 아니다. 이 2c는 더 기초적이고 이해하기 쉽기 때문에


-2
awk -v sep=. 'BEGIN{ORS=OFS="";for(i=1;i<ARGC;i++){print ARGV[i],ARGC-i-1?sep:""}}' "${arr[@]}"

또는

$ a=(1 "a b" 3)
$ b=$(IFS=, ; echo "${a[*]}")
$ echo $b
1,a b,3
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.