포크 2개

포크 2개

모든 요소를 ​​반복하지 않고 전체 배열([key]=value)을 인쇄하는 방법이 있습니까?

몇 가지 요소가 포함된 배열을 생성한다고 가정해 보겠습니다.

declare -A array
array=([a1]=1 [a2]=2 ... [b1]=bbb ... [f500]=abcdef)

전체 배열을 다시 인쇄할 수 있습니다.

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

${!array[@]}그러나 Bash는 모든 배열 요소(키 와 값) 를 한 번에 가져오는 방법을 이미 알고 있는 것 같습니다 ${array[@]}.

반복하지 않고 bash에서 이 정보를 인쇄하도록 하는 방법이 있습니까?

편집:
typeset -p array이렇게 하세요!
하지만 한 번에 접두사와 접미사를 모두 제거할 수는 없습니다.

a="$(typeset -p array)"
b="${a##*(}"
c="${b%% )*}"

출력의 key=value 부분만 가져오거나 인쇄하는 더 깔끔한 방법이 있습니까?

답변1

나는 당신이 거기에서 두 가지 다른 것을 요구하고 있다고 생각합니다.

반복하지 않고 bash에서 이 정보를 인쇄하도록 하는 방법이 있습니까?

예, 하지만 루프를 사용하는 것만큼 좋지는 않습니다.

출력의 key=value 부분만 가져오거나 인쇄하는 더 깔끔한 방법이 있습니까?

응, for루프야. 장점은 외부 프로그램이 필요 없고 간단하며 당황하지 않고 정확한 출력 형식을 쉽게 제어할 수 있다는 것입니다.


declare -p( )의 출력을 처리하려는 솔루션은 typeset -pa) 변수 자체에 괄호나 대괄호가 포함될 가능성과 b) declare -p해당 출력이 셸에 대한 유효한 입력이 되도록 추가해야 하는 인용문을 처리해야 합니다.

예를 들어 b="${a##*(}"키/값에 여는 대괄호가 포함되어 있으면 확장 시 값의 일부가 소모됩니다. 사용 ##하고 제거했기 때문입니다.가장 긴접두사. 에 대해서도 마찬가지입니다 c="${b%% )*}". 인쇄된 템플릿을 더 정확하게 일치시킬 수는 있지만 declare참조하는 모든 것을 원하지 않으면 여전히 어려움에 직면하게 됩니다.

꼭 필요한 경우가 아니면 좋지 않아 보입니다.

$ declare -A array=([abc]="'foobar'" [def]='"foo bar"')
$ declare -p array
declare -A array='([def]="\"foo bar\"" [abc]="'\''foobar'\''" )'

루프를 사용하면 for필요에 따라 출력 형식을 선택하는 것이 더 쉽습니다.

# without quoting
$ for x in "${!array[@]}"; do printf "[%s]=%s\n" "$x" "${array[$x]}" ; done
[def]="foo bar"
[abc]='foobar'

# with quoting
$ for x in "${!array[@]}"; do printf "[%q]=%q\n" "$x" "${array[$x]}" ; done
[def]=\"foo\ bar\"
[abc]=\'foobar\'

거기에서도단순한그렇지 않으면 출력 형식을 변경하십시오(키 주위의 괄호를 제거하고 모든 키/값 쌍을 한 줄에 입력하십시오...). 셸 자체가 아닌 다른 것을 참조해야 하는 경우에도 직접 참조해야 하지만 최소한 작업할 원시 데이터가 있어야 합니다. (키나 값에 줄 바꿈이 있는 경우 일부 인용이 필요할 수 있습니다.)

printf "[%s]=%s" "${x@Q}" "${array[$x]@Q}"현재 Bash(내 생각에는 4.4)에서는 printf "%q=%q". ( 배열의 극단적인 경우로 인용하고 있지만 key 그렇지 않습니다.)@%q

for 루프가 작성하기에 너무 피곤해 보인다면 함수로 저장하십시오(여기에서는 인용되지 않음).

printarr() { declare -n __p="$1"; for k in "${!__p[@]}"; do printf "%s=%s\n" "$k" "${__p[$k]}" ; done ;  }  

그런 다음 사용하십시오.

$ declare -A a=([a]=123 [b]="foo bar" [c]="(blah)")
$ printarr a
a=123
b=foo bar
c=(blah)

인덱스 배열에도 작동합니다.

$ b=(abba acdc)
$ printarr b
0=abba
1=acdc

답변2

declare -p array
declare -A array='([a2]="2" [a1]="1" [zz]="Hello World" [b1]="bbb" [f50]="abcd" )'

포크 2개

아마도 이것은:

printf "%s\n" "${!array[@]}"
a2
a1
f50
zz
b1

printf "%s\n" "${array[@]}"
2
1
abcd
Hello World
bbb

printf "%s\n" "${!array[@]}" "${array[@]}" | pr -2t
a2                              2
a1                              1
f50                             abcd
zz                              Hello World
b1                              bbb

포크 3개

아니면 이거:

paste -d= <(printf "%s\n" "${!array[@]}") <(printf "%s\n" "${array[@]}")
a2=2
a1=1
f50=abcd
zz=Hello World
b1=bbb

포크 없음

비교하기 위해서

for i in "${!array[@]}";do printf "%s=%s\n" "$i" "${array[$i]}";done
a2=2
a1=1
f50=abcd
zz=Hello World
b1=bbb

실행 시간 비교

최종 구문은 포크를 사용하지 않으므로 더 빠를 수 있습니다.

time printf "%s\n" "${!array[@]}" "${array[@]}" | pr -2t | wc
      5      11      76
real    0m0.005s
user    0m0.000s
sys     0m0.000s

time paste -d= <(printf "%s\n" "${!array[@]}") <(printf "%s\n" "${array[@]}") | wc
      5       6      41
real    0m0.008s
user    0m0.000s
sys     0m0.000s

time for i in "${!array[@]}";do printf "%s=%s\n" "$i" "${array[$i]}";done | wc
      5       6      41
real    0m0.002s
user    0m0.000s
sys     0m0.001s

그러나 배열이 더 커지면 이 주장은 더 이상 유효하지 않습니다. 소규모 공정에서는 포크를 줄이는 것이 효과적이라면, 대규모 공정에서는 특수 도구를 사용하는 것이 더 효과적입니다.

for i in {a..z}{a..z}{a..z};do array[$i]=$RANDOM;done


time printf "%s\n" "${!array[@]}" "${array[@]}" | pr -2t | wc
  17581   35163  292941
real    0m0.150s
user    0m0.124s
sys     0m0.036s

time paste -d= <(printf "%s\n" "${!array[@]}") <(printf "%s\n" "${array[@]}") | wc
  17581   17582  169875
real    0m0.140s
user    0m0.000s
sys     0m0.004s

time for i in "${!array[@]}";do printf "%s=%s\n" "$i" "${array[$i]}";done | wc
  17581   17582  169875
real    0m0.312s
user    0m0.268s
sys     0m0.076s

논평

이제 그(두 갈래로 갈라진) 다음을 사용하는 솔루션동맹을 맺으세요, 변수에 다음이 포함된 경우새로운 팀. 이 경우 유일한 방법은 for루프를 실행하는 것입니다.

StackOverflow에 더 안정적이고 자세한 답변이 있습니다.

답변3

KBash 5.1에서는 다음과 같은 값을 사용하여 연관 배열을 매우 간단한 방식으로 표시할 수 있습니다 ${arr[@]@K}.

$ declare -A arr
$ arr=(k1 v1 k2 v2)
$ printf "%s\n" "${arr[@]@K}"
k1 "v1" k2 "v2" 

~에서배쉬 5.1 문서:

헤헤. 새로운 "K" 매개변수 변환은 연관 배열을 키-값 쌍으로 표시합니다.

이에 대한 좋은 설명이 있습니다.Bash 참조 매뉴얼 → 3.5.3 쉘 매개변수 확장:

${parameter@operator}

케이
참조된 키-값 쌍의 시퀀스로 인덱스 배열 및 연관 배열의 값을 인쇄하는 것을 제외하고 매개변수 값의 가능한 인용 버전을 생성합니다(배열 참조).

답변4

~부터조판원하는 것을 수행하려면 출력을 편집하면 되지 않습니까?

typeset -p array | sed s/^.*\(// | tr -d ")\'\""  | tr "[" "\n" | sed s/]=/' = '/

주어진

a2 = 2  
a1 = 1  
b1 = bbb 

어디

array='([a2]="2" [a1]="1" [b1]="bbb" )'

장황하지만 형식 지정이 어떻게 작동하는지 쉽게 알 수 있습니다. 점점 더 많은 콘텐츠로 파이프라인을 실행하면 됩니다.sed그리고주문하다. 당신의 예쁜 인쇄 취향에 맞게 수정해보세요.

관련 정보