때때로 내보낸 bash 함수를 Perl에서 볼 수 있습니다.

때때로 내보낸 bash 함수를 Perl에서 볼 수 있습니다.

내 Redhat 9, OpenBSD 4.9, FreeBSD 10, Macos X, LinuxMint 17.3 및 Ubuntu 14.04.4는 다음 명령을 실행할 때 모두 OK로 인쇄됩니다.

myfunc() { echo OK; }
export -f myfunc
perl -e open\(\$fh,\"\|-\",\"@ARGV\"\)\;close\$fh\; /bin/bash\ -c\ myfunc\\\ a

내 Ubuntu 16.04.1은 다음을 제공합니다.

bash: myfunc: command not found

하지만 삭제하면 \\\ a작동합니다.

perl -e open\(\$fh,\"\|-\",\"@ARGV\"\)\;close\$fh\; /bin/bash\ -c\ myfunc

내 시스템에 뭔가 잘못 구성된 것 같습니다. 그런데 무엇을 찾아야 합니까?

편집하다

thrig는 더 짧은 버전을 찾았지만 그것도 실패했습니다. 이것을 사용하여 실패한 시스템과 실패하지 않은 시스템을 추적했습니다.

stdout strace -ff perl -e 'system @ARGV' /bin/bash\ -c\ myfunc\\\ a|grep bash

실패하다:

execve("/usr/bin/perl", ["perl", "-e", "system @ARGV", "/bin/bash -c myfunc\\ a"], [/* 71 vars */]) = 0
[pid  7728] execve("/bin/sh", ["sh", "-c", "/bin/bash -c myfunc\\ a"], [/* 71 vars */]) = 0
[pid  7729] execve("/bin/bash", ["/bin/bash", "-c", "myfunc a"], [/* 70 vars */]) = 0

실패 없음:

execve("/usr/bin/perl", ["perl", "-e", "system @ARGV", "/bin/bash -c myfunc\\ a"], [/* 20 vars */]) = 0
[pid 26497] execve("/bin/sh", ["sh", "-c", "/bin/bash -c myfunc\\ a"], [/* 20 vars */]) = 0
[pid 26498] execve("/bin/bash", ["/bin/bash", "-c", "myfunc a"], [/* 20 vars */]) = 0

매우 비슷해 보입니다. \\\ a두 시스템 모두에서 지정된 항목을 제거합니다 .

execve("/usr/bin/perl", ["perl", "-e", "system @ARGV", "/bin/bash -c myfunc"], [/* 71 vars */]) = 0
[pid  7826] execve("/bin/bash", ["/bin/bash", "-c", "myfunc"], [/* 71 vars */]) = 0

sh -c따라서 Perl은 명령이 하나만 있으면 제거합니다 . sh -cUbuntu 16.04의 기능을 활용해 볼까요 ?

/bin/shdash두 시스템 모두 에서 .

편집 2

env이 기능을 보여주세요. 이는 두 시스템 모두에서 환경의 일부인 기능을 보여줍니다.

perl -e 'system @ARGV' /bin/bash\ -c\ env

Ubuntu 16.04 및 운영 체제 1개:

BASH_FUNC_myfunc%%=() {  echo OK
}

기타 작업 시스템:

BASH_FUNC_myfunc()=() {  echo OK
}

그러나 이는 작업 시스템에 대한 정의만 보여줍니다.

perl -e 'system @ARGV' /bin/bash\ -c\ env';true'

편집 3

해결책:

myfunc() { echo OK; }
export -f myfunc
perl -e open\(\$fh,\"\|-\",@ARGV\)\;close\$fh\; /bin/bash -c myfunc\ a

답변1

문제는 /bin/shDebian이나 Ubuntu( dash) 또는 OpenBSD와 같은 시스템이환경에서 제거%bash로 내보낸 함수를 인코딩하는 데 사용되는 문자를 포함하여 이름에 와 같은 이상한 문자가 포함된 변수입니다 BASH_FUNC_foo%%=() { ....

|-from open함수 뒤에 인수 목록이 아닌 단일 인수가 오고 해당 인수에 쉘 메타 문자(백슬래시가 그 중 하나임)가 포함되어 있는 경우 Perl은 이를 직접 사용하는 /bin/sh -c대신 인수로 전달합니다.execvp(2)

Perl의 , 및 와 system같은 기능 에도 동일하게 적용되며 에 문서화되어 있습니다 . execopen2perldoc -f system

더 간단한 예:

$ foo(){ echo foo; }; export -f foo

$ perl -e 'system shift' '/bin/bash -c foo\ a'
/bin/bash: foo: command not found
$ perl -e 'system shift' '/bin/bash -c foo'
foo
$ perl -e 'system shift' '/bin/bash -c "foo"'
/bin/bash: foo: command not found

$ perl -e 'open F, "|-", shift' '/bin/bash -c foo\ a'
/bin/bash: foo: command not found
$ perl -e 'open F, "|-", shift' '/bin/bash -c foo'
foo

해결 방법은 사용자의 command 를 사용하여 외부 명령을 실행하는 것입니다 $ENV{SHELL}. 그러면 모든 셸 기능을 원활하게 사용할 수 있습니다.

perl -e 'open F, "|-", $ENV{SHELL}, "-c", "@ARGV"' '/bin/bash -c "foo a"'

답변2

시스템 간에 내보낸 bash 기능의 이식성에 문제가 있습니다. 네, 그렇군요.

간단히 휴대성을 향상시키세요.

$ touch myfunc
$ chmod a+x myfunc

#! /usr/bin/env bash그리고 shebang 줄부터 시작하여 필요한 bash 코드를 파일에 넣으세요 . ( env복종 $PATH하세요.)

그런 다음 변형이 동작을 얼마나 좋아 sh하거나 준수하는지보다는 프로그램(gnu 병렬 포함)의 포크+실행 기능에 의존합니다 .dashbash

관련 정보