포크 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는 한 번의 "go"로 모든 배열 요소(key 및 value 모두)를 가져오는 방법을 이미 알고 있는 것 같습니다 ${array[@]}.

루프 없이 bash에서 이 정보를 인쇄하도록 하는 방법이 있습니까?

편집:
typeset -p array그렇군요!
그러나 단일 대체에서 접두사와 접미사를 모두 제거할 수는 없습니다.

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

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

답변1

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

루프 없이 bash에서 이 정보를 인쇄하도록 하는 방법이 있습니까?

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

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

응, 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\'

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

현재 Bash(4.4인 것 같아요) printf "[%s]=%s" "${x@Q}" "${array[$x]@Q}"에서는 printf "%q=%q". 좀 더 멋진 인용 형식을 생성하지만, 작성하는 것을 기억해야 하는 작업이 조금 더 늘어납니다. (그리고 인용하지 않는 배열 키로 의 코너 케이스를 인용합니다 .)@%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" 

로부터Bash 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그리고tr명령. 예쁜 인쇄 취향에 맞게 수정하세요.

관련 정보