Bash를 통해 다음과 같이 명령을 실행하고 싶다고 가정해 보겠습니다.
/bin/bash -c "ls -l"
Bash 매뉴얼 페이지에 따르면 다음과 같이 실행할 수도 있습니다.
# don't process arguments after this one
# | pass all unprocessed arguments to command
# | |
# V V
/bin/bash -c ls -- -l
하지만 작동하지 않는 것 같습니다(무시되는 것 같습니다). 내가 뭔가 잘못하고 있는 걸까요, 아니면 매뉴얼 페이지를 잘못 해석하고 있는 걸까요?
남성에 관한 관련 인용문:
-c 옵션이 있으면 문자열에서 명령을 읽습니다. 문자열 뒤에 매개변수가 있으면 $0부터 시작하는 위치 매개변수에 할당됩니다.
그리고
A - 옵션의 끝을 나타내며 추가 옵션 처리를 비활성화합니다. -- 이후의 모든 인수는 파일 이름 및 인수로 처리됩니다.
답변1
매뉴얼 페이지에 대한 해석이 잘못되었습니다. 먼저 옵션의 끝을 나타내는 부분은 --
하려는 작업과 관련이 없습니다. -c
그 시점부터 나머지 명령줄은 덮어쓰기되어 더 이상 bash의 옵션 처리를 거치지 않습니다. 즉, --
bash에서 옵션 끝 표시로 처리되는 대신 명령에 전달된다는 의미입니다.
두 번째 오류는 추가 인수가 명령에 인수로 전달되지 않고 시작된 셸 프로세스에 위치 인수로 할당된다는 것입니다. 따라서 수행하려는 작업은 다음 중 하나로 수행할 수 있습니다.
/bin/bash -c 'echo "$0" "$1"' foo bar
/bin/bash -c 'echo "$@"' bash foo bar
첫 번째 경우에는 echo 인수가 명시적으로 전달되고 $0
, $1
두 번째 경우에는 "$@"
"$0을 제외한 모든 위치 인수"에 일반 확장이 사용됩니다. 이 경우에는 사용할 무언가를 전달해야 한다는 점에 유의하세요 $0
. 저는 "bash"를 선택했습니다. 왜냐하면 이것이 $0
일반적이지만 다른 것도 가능하기 때문입니다.
이렇게 하는 이유는 제공한 인수를 나열한 명령에 직접 전달하는 것보다 다음과 같습니다. 문서에 "명령에스문자열에서 ""(복수형)를 읽습니다. 즉, 이 프로그램을 사용하면 다음을 수행할 수 있습니다.
/bin/bash -c 'mkdir -p -- "$1" && cd -P -- "$1" && touch -- "$2"' bash dir file
그러나 원래 목표를 달성하는 더 좋은 방법은 다음을 env
대신 사용하는 것일 수 있습니다 bash
.
/usr/bin/env -- "ls" "-l"
셸이 제공하는 기능이 필요하지 않다면 사용할 이유가 없습니다. env
이 경우 더 빠르고 간단하며 입력이 덜 필요합니다. 그리고 쉘 메타 문자나 공백이 포함된 파일 이름을 안전하게 처리할 수 있는지 확인하기 위해 너무 열심히 생각할 필요가 없습니다.
답변2
귀하의 목표가 무엇인지는 잘 모르겠지만 단지 구축하고 싶다면루브 골드버그 기계– “아주 간단한 작업을 매우 복잡한 방식으로 수행하기 위해 의도적으로 과도하게 설계되거나 과도하게 설계된 장치, 발명, 장치 또는 장치” – 그런 다음 시도해 보십시오.
sh -c 'ls $0' -l
또는
sh -c 'ls $1' supercalifragilisticexpialidocious -l
심지어
sh -c 'ls -$0' l
이러한 작업이 어떻게 작동하는지 이해할 수 있어야 합니다.신 괴짜의 대답. ~처럼 데릭 마하르 댓글, 스크립트 매개변수(다음 명령 문자열 -c
)는 큰따옴표 대신 작은따옴표로 묶어야 한다는 점을 강조해야 합니다. 그렇지 않으면 상위 셸(위 명령줄을 입력한)은 상위 셸의 컨텍스트에서 스크립트 매개변수의 위치 인수를 구문 분석합니다. 예를 들어,
$ set -- The quick brown fox
$ sh -c 'echo "$0" "$1"' foo bar baz
foo bar
$ sh -c "echo '$0' '$1'" foo bar baz
bash The
답변3
그것은 그 모든 것보다 간단하고 당신은 꽤 가깝습니다.
전체 명령이 단일 문자열로 전달되도록 공백을 이스케이프 처리합니다. 스크립트는 다음과 같습니다.
bash -c "ls\ -l\ $@"
이스케이프되지 않은 공백으로 구분하여 추가 명령을 추가할 수 있습니다.
# ↓ unescaped
bash -c "cd\ ~/junk ls\ -l\ $@"
# ↑↑ ↑↑ ↑↑ escaped
junk
이 명령에서 와 사이의 공백은 ls
이스케이프 처리되지 않은 유일한 공백이므로 두 명령을 구분하는 역할을 합니다.