병렬 프로세스를 사용하여 대화형 bash 루프 속도를 높이지만 루프 내부에 연관 배열을 만들어야 합니다.

병렬 프로세스를 사용하여 대화형 bash 루프 속도를 높이지만 루프 내부에 연관 배열을 만들어야 합니다.

Bash를 사용하면 파일 목록을 나타내는 인덱스 배열이 있습니다.

a=("1.json" "2.json" "3.json" ... "5309.json")

이 JSON 파일의 두 데이터 필드를 두 개의 연관 배열로 구문 분석합니다.

declare -A idArr
declare -A valueArr

for i in "${a[@]}"; do
    jqId="$(jq -M ".fileId" <"${i}")"
    jqValue="$(jq -M ".value" <"${i}")"
    # If there are already items in the associative array, add the new items separated by a newline
    idArr[${i}]="${idArr[${i}]}${idArr[${i}]:+$'\n'}${jqId}"
    valueArr[${jqId}]="${valueArr[${jqId}]}${valueArr[${jqId}]:+$'\n'}${jqValue}"
done

한 번에 하나의 파일을 반복하기 때문에 모든 파일을 처리하는 데 꽤 시간이 걸립니다. 루프 내에서 생성된 연관 배열은 루프가 완료된 후에도 계속해서 범위를 초과해야 한다는 요구 사항이 있습니다.

parallel여러 배열 항목을 동시에 처리하면서도 연관 배열에 데이터를 제공할 수 있는 방법(예: 처리 또는 기타 방법 사용)이 있습니까 ?

답변1

여기에서 속도가 느릴 수 있는 점은 jq파일당 두 개의 s를 실행하고 프로세스를 포크하고 jq 그 안에서 실행하는 것이 아마도 작은 json 파일을 처리하는 것보다 작업량이 훨씬 더 많다는 점입니다.

read0() { IFS= read -rd '' "$@"; }
add_line() {
  typeset -n _var="$1"
  _var+=${_var:+$'\n'}$2
}
shopt -s extglob failglob lastpipe
set -o pipefail

typeset -A idArr valueArr

jq -j '[input_filename, .fileId, .value] |
       map(gsub("\u0000"; "") + "\u0000") | add
      ' -- +([0123456789]).json |
  while read0 file && read0 id && read0 value; do
    add_line "idArr[$file]"    "$id"
    add_line "valueArr[$file]" "$var"
  done

한 번만 실행됩니다 jq. jqbash가 루프에서 병렬로 읽을 때 NUL로 구분하여 파일 이름, ID 및 값(있는 경우 NUL 제거)을 인쇄합니다.

중요한 팁: 하다아니요약간 위장되어 있기 add_line때문에 명령 주입 취약점이 될 수 있으므로 임의의 파일 이름으로 호출하십시오 . 예를 들어 대신 을 사용 하고 이라는 파일이 있으면 재부팅됩니다!typeset -neval*.json+([0123456789]).json$(reboot).json

현재 버전의 bash에서는 큰따옴표 대신 작은따옴표를 사용하여 이 문제를 해결할 수 있지만 idArr[$file], valueArr[$file]향후 버전의 bash에서는 nameref 역참조에 대해 이러한 확장을 수행하지 않기로 결정할 수 있으므로 이는 미래의 증거가 아닐 수 있습니다.

또는 잘못 설계된 이름 참조를 제거하고 eval이를 명시적으로 사용하여 이러한 취약점을 제거할 수 있습니다.

add_line() {
  eval "$1+=\${$1:+\$'\\n'}\$2"
}

그리고 반드시 다음과 같이 호출하세요.

    add_line 'idArr[$file]'    "$id"
    add_line 'valueArr[$file]' "$var"

그런 다음 소독을 사용 *.json하거나 필요하지 않을 수 있습니다 ."${a[@]}"

"매개변수 목록이 너무 깁니다." 오류가 발생하면 jq ... +([0123456789]).json로 바꾸십시오 printf '%s\0' +([0123456789]).json | xargs -r0 jq ....

xargsGNU '를 사용하여 -P이들 중 일부를 병렬로 실행할 수도 있지만 명령 출력의 직렬화가 보장되지 않아 개별 s의 출력이 서로 얽힐 수 있으므로 jq권장하지 않습니다 . GNU는 그렇습니다. 그러나 (아마도) 짧은 JSON 파일을 구문 분석하는 것과 같은 간단한 작업에 비해 오버헤드가 많기 때문에 추가 이점이 없을 수도 있습니다.xargsjqparallel


1은 표준 입력 jq으로 처리되므로 -엄밀히 말하면 그러한 이름의 파일이 배열 (또는 대신 $aglob 확장자 )에 존재하는 경우 이를 .**.json./-

관련 정보