배열의 각 멤버 앞에 추가하고 추가하는 방법은 무엇입니까?

배열의 각 멤버 앞에 추가하고 추가하는 방법은 무엇입니까?

배열이 있습니다.

CATEGORIES=(one two three four)

매개변수 확장을 사용하여 각 배열 구성원 앞에 다음을 추가할 수 있습니다.

echo ${CATEGORIES[@]/#/foo }

같은 방법으로 각 배열 멤버에 추가할 수 있습니다.

echo ${CATEGORIES[@]/%/ bar}

어떻게 둘 다 가질 수 있나요? 다음 중 어느 것도 작동하지 않습니다.

echo ${CATEGORIES[@]/(.*)/foo \1 bar}
echo ${CATEGORIES[@]/(.*)/foo $1 bar}
echo ${CATEGORIES[@]/(.*)/foo ${BASH_REMATCH[1]} bar}

답변1

최종 목표에 따라 다음을 사용할 수 있습니다 printf.

$ a=(1 2 3)
$ printf "foo %s bar\n" "${a[@]}"
foo 1 bar
foo 2 bar
foo 3 bar

printf형식 문자열은 모든 인수가 사용될 때까지 재사용되므로 문자열 집합에 일부 형식을 적용하는 쉬운 방법을 제공합니다.

답변2

기록의 경우 with 배열 요소에 중괄호와 같은 확장을 여는 연산자가 zsh있습니다 . ${^array}그래서:

$ a=(one two three)
$ b=('foo '${^a}' bar')
$ printf '<%s>\n' $b
<foo one bar>
<foo two bar>
<foo three bar>

검색 및 바꾸기도 에서 작동합니다 zsh.

$ printf '<%s>\n' ${a//(#m)*/foo $MATCH bar}
<foo one bar>
<foo two bar>
<foo three bar>

그리고 printf -v배열에서:

$ b=(); printf -v b 'foo %s bar' "$a[@]"
$ printf '<%s>\n' $b
<foo one bar>
<foo two bar>
<foo three bar>

echo ${CATEGORIES[@]/(.*)/foo \1 bar}작성된 경우 ksh93:

$ printf '<%s>\n' "${CATEGORIES[@]/@(.*)/foo \1 bar}"
<foo one bar>
<foo two bar>
<foo three bar>

답변3

p='* "foo  '
s='  bar $USER' 
CATEGORIES=(one two three four)
CATEGORIES=("${CATEGORIES[@]/#/$p}")
CATEGORIES=("${CATEGORIES[@]/%/$s}")

paste <(printf '[%s]\n' "${!CATEGORIES[@]}") \
      <(printf '%s\n'    "${CATEGORIES[@]}")

산출:

[0] * "foo  one  bar $USER
[1] * "foo  two  bar $USER
[2] * "foo  three  bar $USER
[3] * "foo  four  bar $USER

답변4

이것은특별한 경우추가된(또는 앞에 추가된) 문자열이 다음과 같은 경우에 적합한 솔루션은 다음과 같습니다.단일 문자, 새 배열의 값이 필요하지 않습니다.

array=( aa bb cc )
IFS="]"                        # or, IFS="["
echo "${array[*]/#/ [}$IFS"    # or, echo "$IFS${array[*]/%/] }

출력을 생성합니다 [aa] [bb] [cc].

  • 인용된 형식은 "${array[*]}"각 쌍 사이에 구분 기호를 추가합니다(제약조건이 나타나는 위치인 의 첫 번째 문자).]IFS
  • ${array[*]/#/ [} [각 요소 앞에 추가 (또는 /%/양식 추가)
  • 마지막으로 확장된 값에 후행 ](from )을 추가합니다.IFS

이 단계를 하나씩 적용하면 다음과 같은 결과를 얻을 수 있습니다.

aa]bb]cc
 [aa] [bb] [cc
 [aa] [bb] [cc]

(데이터를 새 어레이로 쉽게 복원할 수도 있습니다.만약에이 값에는 공백이 포함되어 있지 않습니다. )

한 줄에서 다양한 접두사/접미사 작업을 수행할 수 있습니다.

for ii in "${array[@]/#/foo }"; do echo "${ii/%/ bar}"; done

printf다음은 새 어레이에 복사하는 보다 강력한 솔루션입니다 .

mapfile -d '' newarray < <(printf "foo %s bar\0" "${array[@]}")

서브 쉘을 희생하더라도 ( bash-4.4 필요 mapfile -d)

마지막으로 새 배열에 복사하고 필요한 경우 희소 배열과 연관 배열을 처리할 수도 있는 루프 변형이 있습니다.

declare -a array newarray   # -a for indexed array, -A for associative
array=( one two three )
for ii in "${!array[@]}"; do
  printf -v "newarray[$ii]" "foo %s bar" "${array[$ii]}"
done

( printf필수는 아니지만 직접 할당할 수 있지만 IMHO가 더 명확합니다. bash(아직!) 그러나 배열로 인쇄를 지원하면 zsh루프 없는 복사 및 단일 라인 변환이 가능합니다. 위의 Stéphane 답변을 참조하세요.)


여기서 유용한 점은 확장의 일치 문자열에 대한 자리 표시자로 bash제네릭이 지원되는 경우 &(예: $MATCH) 입니다.zsh코드는 거기 있어요(그리고 오랫동안 사용해 왔지만) 안타깝게도 아직 활성화되지 않았습니다( shouldexp_replacement()참조subst.c). 활성화하면( #if 0두 번 변경한 후 다시 컴파일) 예상대로 작동합니다.

array=( aa bb cc )
newarray=( "${array[@]/*/foo & bar}" )

그렇군요. 다음 버전에서는 가능할 수도 있겠네요...

compgen접두사/접미사 작업이 있습니다(지원되지만 &여기서 사용할 수 있는 방식은 아닙니다). 우리가 할 수 있는 최선은 Mulu의 printf솔루션보다 더 나쁩니다.

compgen -P "foo " -S " bar" -W "${array[*]}"

( -W단 하나의 옵션만 필요하므로 배열이 평면화되어 공백 등이 있는 값에 문제가 발생한다는 점에 유의하세요 IFS)

관련 정보