bash의“mapfile”을 파이프 할 수는 없지만… 왜 그렇습니까? -name “mysqldump*” |

특정 디렉토리의 모든 파일을 bash 배열로 가져 오려고합니다 (이름에 줄 바꿈이없는 파일이 있다고 가정).

그래서:

myarr=()
find . -maxdepth 1  -name "mysqldump*" | mapfile -t myarr; echo "${myarr[@]}"

빈 결과!

파일을 사용하는 원형 교차로 방법을 사용하는 경우 임시 또는 다른 방법으로 :

myarr=()
find . -maxdepth 1  -name "mysqldump*" > X
mapfile -t myarray < X
echo "${myarray[@]}"

결과!

그런데 왜 mapfile파이프에서 제대로 읽지 않습니까?



답변

보낸 사람 man 1 bash:

파이프 라인의 각 명령은 별도의 프로세스 (즉, 서브 쉘)로 실행됩니다.

이러한 서브 쉘은 기본 쉘에서 변수를 상속하지만 독립적입니다. 이것은 mapfile원래 명령에서 자체적으로 작동 한다는 것을 의미 합니다 myarr. 그런 다음 echo(파이프 외부에 있음) 빈 myarr(메인 쉘 )을 인쇄합니다 myarr.

이 명령은 다르게 작동합니다.

find . -maxdepth 1 -name "mysqldump*" | { mapfile -t myarr; echo "${myarr[@]}"; }

이 경우 mapfileecho동일한에서 작동 myarr(하지의 주요 쉘이다 myarr).

메인 쉘을 변경하려면 메인 쉘에서 정확하게 myarr실행해야합니다 mapfile. 예:

myarr=()
mapfile -t myarr < <(find . -maxdepth 1 -name "mysqldump*")
echo "${myarr[@]}"

답변

Bash는 서브 쉘 환경에서 파이프 라인의 명령을 실행하므로 그 안에서 발생하는 변수 할당 등은 쉘의 나머지 부분에 표시되지 않습니다.

zsh와 ksh는 기본 쉘에서 마지막 부분을 실행하는 반면 대시 (데비안 /bin/sh)와 busybox sh도 비슷합니다. Bash shopt -s lastpipe에서도 동일한 작업을 수행 할 수 있지만 작업 제어가 비활성화 된 경우에만 작동하므로 기본적으로 대화식 쉘에서는 작동하지 않습니다.

그래서:

$ bash -c 'x=a; echo b | read x; echo $x'
a
$ bash -c 'shopt -s lastpipe; x=a; echo b | read x; echo $x'
b

( read그리고 mapfile같은 문제가 있습니다.)

또는 Attie가 언급 한대로 일반화 된 파이프처럼 작동하며 Bash, ksh 및 zsh에서 지원되는 프로세스 대체를 사용하십시오 .

$ bash -c 'x=a; read x < <(echo b); echo $x'
b

POSIX는 파이프 라인의 일부가 서브 쉘에서 실행되는지 여부를 지정하지 않은 상태로 두므로, 어떤 쉘도 이것에서 “잘못”되었다고 말할 수 없습니다.


답변

Kamil이 지적했듯이 파이프 라인의 각 요소는 별도의 프로세스입니다.

다음 프로세스 대체 를 사용 하여 현재 인터프리터에 호출이 남아 find있는 다른 프로세스에서 실행 mapfile하여 myarr나중에 액세스 할 수 있습니다 .

myarr=()
mapfile -t myarr < <( find . -maxdepth 1  -name "mysqldump*" )
echo "${myarr[@]}"

b < <( a )a | b파이프 라인 연결 방식 과 유사하게 작동 합니다. 차이점은 b여기 “에서 실행 됩니다 .