병렬 처리를 사용하여 배열에 추가할 수 없습니다.

병렬 처리를 사용하여 배열에 추가할 수 없습니다.

parallel문제 없이 for 루프를 사용할 때 배열에 추가할 수 없습니다 .

병렬 예:

append() { arr+=("$1"); } 
export -f append

parallel -j 0 append ::: {1..4}
declare -p arr

산출:

-bash: declare: arr: not found

루프의 경우:

for i in {1..4}; do arr+=("$i"); done
declare -p arr

산출:

declare -a arr=([0]="1" [1]="2" [2]="3" [3]="4")

첫 번째 예는 루프에 대한 기능적 스타일을 번역한 것 같은데, 무슨 일이 벌어지고 있는 걸까요?

답변1

귀하의 스크립트 는 명령을 병렬로 실행하는 스크립트 parallel인 GNU 스크립트인 것 같습니다 .perl

전달한 명령이 해당 셸에 의해 해석되도록 어느 셸에서 호출되었는지 확인하는 것은 매우 어렵지만 이를 위해 별도의 프로세스에서 해당 셸의 새로운 호출을 실행합니다.

실행하는 경우:

bash-5.2$ env SHELLOPTS=xtrace PS4='bash-$$> ' strace -qqfe /exec,/exit -e signal=none  parallel -j 0 append ::: {1..4}
execve("/usr/bin/parallel", ["parallel", "-j", "0", "append", ":::", "1", "2", "3", "4"], 0x7ffe5e848c90 /* 56 vars */) = 0
[...skipping several commands run by parallel during initialisation...]
[pid  7567] execve("/usr/bin/bash", ["/usr/bin/bash", "-c", "append 1"], 0x55a2615f03e0 /* 67 vars */) = 0
bash-7567> append 1
bash-7567> arr+=("$1")
[pid  7567] exit_group(0)               = ?
[pid  7568] execve("/usr/bin/bash", ["/usr/bin/bash", "-c", "append 2"], 0x55a2615f03e0 /* 67 vars */) = 0
[pid  7568] exit_group(0)               = ?
[pid  7569] execve("/usr/bin/bash", ["/usr/bin/bash", "-c", "append 3"], 0x55a2615f03e0 /* 67 vars */) = 0
bash-7568> append 2
bash-7568> arr+=("$1")
[pid  7569] exit_group(0)               = ?
[pid  7570] execve("/usr/bin/bash", ["/usr/bin/bash", "-c", "append 4"], 0x55a2615f03e0 /* 67 vars */) = 0
bash-7569> append 3
bash-7569> arr+=("$1")
[pid  7570] exit_group(0)               = ?
bash-7570> append 4
bash-7570> arr+=("$1")
exit_group(0)                           = ?

strace어떤 명령이 어떤 프로세스에 의해 실행되는지 보여줍니다. 이 옵션 xtrace을 사용하면 쉘이 수행하는 작업을 표시합니다.

각 bash 쉘이 자체 bash 쉘에 요소를 추가한 $arr다음 종료되고 물론 자체 메모리 공간(각각의 $arr배열 포함)이 사라지는 것을 볼 수 있습니다. 이 배열은 시스템의 모든 쉘 호출 중 자동으로 공유 $arr되지 않습니다 .bash

어쨌든 명령을 동시에 실행한다는 것은 해당 명령을 다른 프로세스에서 실행하는 것을 의미하므로 호출 셸에서 이러한 기능을 실행할 수 없습니다. 이러한 기능은 별도 프로세스의 새 셸 인스턴스에서 실행되며 arr이러한 셸의 변수를 업데이트합니다. 실행하는 쉘 중 하나입니다 parallel.

bash에는 멀티스레딩 지원이 내장되어 있지 않기 때문에 parallel명령이 셸 내부에 있거나 셸 함수로 구현된 경우에도 각각 자체 메모리가 있는 별도의 프로세스에서 명령을 실행해야 합니다. 다음에서 찾을 수 있습니다:

append 1 & append 2 & append 3 & wait

또는:

append 1 | append 2 | append 3

$arr상위 쉘의 배열도 수정되지 않습니다.

병렬로 시작된 각 작업의 결과를 수집하려는 경우 stdout 또는 파일을 통해 수행할 수 있습니다.

예를 들어:

#! /bin/bash -
do_something() {
  output=$(
    echo "$1: some complex computation or otherwise there would
          be no point using GNU parallel and its big overhead"
  )
  # output the result NUL delimited.
  printf '%s\0' "$output"
}
export -f do_something
readarray -td '' arr < <(
  PARALLEL_SHELL=/bin/bash parallel do_something ::: {1..4}
)
typeset -p arr

(이것은 parallel추측을 피하기 위해 어떤 쉘을 사용해야 하는지 알려줍니다.)

각 셸의 출력을 임시 파일에 저장하고 표준 출력에 순차적으로 덤프 하면 parallel배열의 요소를 올바른 순서로 가져올 수 있습니다.

답변2

parset이것이 GNU Parallel의 일부라는 것을 알아야 합니다 :

$ parset arr echo ::: 1 2 3 4
$ declare -p arr
declare -a arr=([0]="1" [1]="2" [2]="3" [3]="4")

추가되지는 않지만(질문에 대한 유효한 답변이 아님) 여전히 유용할 수 있습니다.

답변3

이것은 작동합니다:

arr+=($(parallel -j 0 echo ::: {1..4}))

와 달리 병렬 인스턴스에 설정되었기 때문에 배열이 누락되었습니다 echo.

관련 정보