좋은 시간.
약간의 문제가 있습니다. bash 스크립트에 이 기능이 있습니다
function denyCheck(){
file=$(readlink -f $(which $(printf "%s\n" "$1")))
if [[ -x $file ]];then
return false
else
return true
fi
}
denyCheck "firefox"
이 함수는 그녀에게 명령이 무엇인지 문자열을 전달합니다. 이는 명령이 있는 원래 경로(예: /usr/lib/firefox/firefox.sh)를 확인하고 파일이 실행 가능하면 true를 반환하고 그렇지 않으면 false를 반환합니다.
하지만 문제는... 매개변수(예: "firefox")가 이를 명령으로 실행하고 브라우저 Firefox를 연다는 것입니다.
매개변수가 실행되지 않도록 하려면 어떻게 해야 합니까?
매우 감사합니다.
답변1
그 이상이어야 합니다:
cmd_canonical_path() {
local cmd_path
cmd_path=$(command -v -- "$1") &&
cmd_path=$(readlink -e -- "$cmd_path") &&
[ -x "$cmd_path" ] &&
REPLY=$cmd_path
} 2> /dev/null
그런 다음 예를 들어 다음을 사용하십시오.
if cmd_canonical_path firefox; then
printf '%s\n' "firefox found in $REPLY executable"
else
printf >&2 '%s\n' "no executable file found for firefox"
fi
셸에서 모든 명령에는 성공(0) 또는 실패(다양한 유형의 실패를 구별하는 데 도움이 되는 값을 갖는 다른 숫자)를 나타내는 종료 상태가 있습니다.
예를 들어, 명령을 실행하는 프로세스에 파일(또는 디렉터리)에 대한 실행 권한이 있는 경우 [
명령은 -x
인수로 전달될 때 true를 반환합니다./path/to/some/file
]
/path/to/some/file
함수에는 반환 전 마지막 명령 실행의 종료 상태(또는 return
호출 시 전달된 숫자)인 종료 상태도 있을 수 있습니다.
if
명령의 성공 또는 실패 상태는 // 문이나 해당 부울 연산자 sum 과 같은 쉘 구성으로 until
확인됩니다 .while
||
&&
주문하다원하는 경우 셸의 부울 값입니다.
cmd1 && cmd2 && cmd3
성공 / true를 반환합니다. 모두 예 이고 cmd1
성공입니다 . 실패해도 실행 되지 않습니다 .cmd2
cmd3
cmd2
cmd1
cmd3
cmd_canonical_path
따라서 위의 경우 성공합니다 command -v -- "$1"
(명령을 찾고 해당 경로를 인쇄하기 위한 표준 내장1 명령; which
일부 유사한 명령이지만 csh 사용자에게만 해당).그리고그런 다음 readlink -e
(정규화된 경로처럼 작동 하지만, 최선의 노력을 다하면서 readlink -f
할 수 없으면 실패를 반환합니다 ) 성공readlink -f
그리고그런 다음 현재 프로세스에는 파일에 대한 실행 권한이 있습니다.그리고그런 다음에만 경로가 REPLY
4번째 변수에 성공적으로 할당됩니다(일반 할당은 항상 성공합니다).
cmd && cmd && cmd
그렇지 않은 경우 함수는 실패(실패한 체인의 첫 번째 명령의 종료 상태)를 반환합니다.
$REPLY
또한 명령에 대한 정식 경로를 결정할 수 없거나 명령을 실행할 수 없는 경우 명령이 수정되지 않고 보존된다는 점도 참고하세요 .
귀하의 접근 방식에는 몇 가지 다른 문제가 있습니다.
- 이것은
$(printf '%s\n' "$1")
별로 의미가 없습니다. sh/bash에서는$1
(적어도 기본값)과 동일하며$IFS
인용되지 않았기 때문에 똑같이 잘못되었습니다. 첫 번째 위치 인수의 내용을 명령에 전달하려는 경우 구문은 입니다cmd "$1"
. - 옵션이 아닌 인수로 처리되도록 명령에 전달된 임의의 데이터를 원하는 경우
--
옵션의 끝을 표시하는 인수 뒤에 이를 전달해야 합니다:which -- "$1"
,readlink -f -- "$(...)"
. return
true
/ 대신 (선택적) 숫자를 인수(함수의 종료 코드)로 허용합니다false
(파일이 실행 가능하면 함수가 true를 반환한다고 말했기 때문에 이를 반대로 한 것 같습니다). 숫자가 전달되지 않으면 함수의 종료 상태는 함수 내에서 실행된 마지막 명령의 종료 상태가 됩니다. 그래서if cmd; then return 0; else return 1; fi
그냥 쓰는 것이 가장 좋습니다cmd; return
. 여기서는 ( 귀하의 경우) 함수의 마지막 명령이기return
때문에 필요하지 않습니다 .cmd
[[ -x $file ]]
- 먼저 성공 여부를 확인하지 않고
which
(을 잊어버리고--
인용했기 때문에 부정확하게$(...)
) 의 출력을 맹목적으로 전달했습니다 .readlink
마지막으로 를 대신 사용하면 zsh
다음 bash
과 같이 할 수 있습니다.
firefox_path==firefox
firefox_canonical_path=$firefox_path:P
firefox
명령의 경로를 가져옵니다 . =firefox
명령의 경로로 확장하여 firefox
명령을 찾을 수 없으면 오류와 함께 셸을 중단합니다. 오류를 차단할 수 있습니다.always
막힌필요한 경우. 이 :P
수정자는 realpath()
GNU의 작업과 유사하게 적용되는 인수에 대해 동일한 작업을 수행합니다 readlink -f
. zsh
의 =cmd
연산자는 실행 경로로만 확장되므로 실행 권한을 확인할 필요가 없습니다 .
¹ 셸에 내장된 구성 요소이므로 셸 설명서에서 해당 설명서를 찾을 수 있습니다. 에 대해서는 예를 bash
참조하세요 info bash command
.
² command -v cmd
출력 cmd
은 cmd
함수 또는 셸 내장 함수이므로 문제가 될 수 있습니다.
³ 표준 절대 경로는 로 시작하고 /
, 심볼릭 링크 구성 요소가 없으며(모두 대상으로 확인됨), / 구성 요소가 없으며 , 두 개 이상의 s 시퀀스가 .
없습니다 ...
/
4는 $REPLY
함수나 쉘 내장 함수의 반환 값에 대한 기본 변수로 자주 사용됩니다(단지 관례일 뿐임). 또는 함수에서 다음을 수행할 수 있습니다.산출결과적으로 호출자는 를 실행합니다 firefox_path=$(cmd_canonical_path firefox)
.
답변2
이것:
function denyCheck(){
func()
표준 함수 선언과 ksh 가 혼합되어 있습니다 function func
. Bash는 이 조합을 지원하고 다른 쉘은 그렇지 않을 수도 있지만 그럴 이유가 없습니다. 그냥 써 denyCheck()
.
여기,
file=$(readlink -f $(which $(printf "%s\n" "$1")))
이는 $(printf ...)
불필요하며 인용되지 않았기 때문에 실제로는 비생산적입니다. 이 명령 대체의 결과는 다음의 영향을 받습니다.분사, 인용된 내용은 "$1"
그렇지 않으므로 대신 사용할 수 있습니다.
which
몇 가지 문제가 있는 것으로 간주되는 표준 POSIX 대안은 다음을 command -v
참조하세요." which "를 사용하지 않는 이유는 무엇입니까? 그러면 무엇을 사용해야 합니까?
둘 사이의 가장 큰 차이점은 command
내장 셸이고 예를 들어 별칭에 대해 알고 있는 반면(대화형 셸에서 실행하는 경우) 그렇지 which
않다는 것입니다(csh를 제외하고 사용하지 않음). 이는 좋은 것일 수도 있고 아닐 수도 있습니다. 예를 들어 사용할 수 있는 경로가 아닌 를 command -v ls
반환할 수 있습니다 .alias ls='ls -vF --color=auto'
--
어떤 경우든 단어 분리 문제를 방지하고 태그 옵션의 끝 부분을 추가하려면 명령 대체를 인용해야 합니다 . 이는 공백을 포함하거나 로 끝나는 드문 경로를 방지하기 위한 것입니다 -
.
file=$(readlink -f -- "$(command -v -- "$1")") # or
file=$(readlink -f -- "$(which -- "$1")")
그 다음에,
return false
단지 버그입니다. return
명령에 숫자가 필요합니다. 그러나 false
오류의 반환 상태를 가져오기 위해 명명된 명령을 실행할 수 있습니다 . 따라서 또는
return 1
just 중 하나를 사용하십시오 false
. (테스트 결과를 반전시키는 것이므로 ! [[ -x "$file" ]]
전체 if
명령문 대신 just를 사용할 수도 있습니다. 이를 작성하면 다음 독자에게 더 명확해질 수 있습니다.)
그래서:
denycheck() {
file=$(readlink -f -- "$(command -v -- "$1")")
if [[ -x "$file" ]]; then
return 1 # command found and executable, falsy result
else
return 0 # not executable, truthy result
fi
}