내 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 -c
Ubuntu 16.04의 기능을 활용해 볼까요 ?
/bin/sh
dash
두 시스템 모두 에서 .
편집 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/sh
Debian이나 Ubuntu( dash
) 또는 OpenBSD와 같은 시스템이환경에서 제거%
bash로 내보낸 함수를 인코딩하는 데 사용되는 문자를 포함하여 이름에 와 같은 이상한 문자가 포함된 변수입니다 BASH_FUNC_foo%%=() { ...
.
|-
from open
함수 뒤에 인수 목록이 아닌 단일 인수가 오고 해당 인수에 쉘 메타 문자(백슬래시가 그 중 하나임)가 포함되어 있는 경우 Perl은 이를 직접 사용하는 /bin/sh -c
대신 인수로 전달합니다.execvp(2)
Perl의 , 및 와 system
같은 기능 에도 동일하게 적용되며 에 문서화되어 있습니다 . exec
open2
perldoc -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 병렬 포함)의 포크+실행 기능에 의존합니다 .dash
bash