나는 다음을 수행합니다.
$ ./input ""
산출:
argc 2
argv[1][0] 0
그러나 프로그램 기반 방식으로 (여러) 빈 따옴표를 전달하려는 경우:
$ python -c 'print "\"\""'
""
./input $(python -c 'print "\"\""')
다음을 제공합니다:
argc 2
argv[1][0] 22 - (22 hex value for ")
그렇다면 어떻게 다음과 같은 것을 생성할 수 있습니까?
$ ./input "" "" "" ""
예제 1과 동일한 결과를 얻습니까?
답변1
존재하다
./input $(cmd)
$(cmd)
따옴표로 묶지 않은 것은 분할+글로브 연산자이기 때문입니다 . 쉘에 의해 검색된 출력은 cmd
후행 줄 바꿈을 모두 제거한 다음 $IFS
특수 인수의 값에 따라 분할한 다음 생성 *.txt
된 단어(예: 현재 디렉토리에 숨겨져 있지 않은 txt 파일 목록)를 사용하여 파일 이름 생성을 수행합니다( 가 없는 후반부 ), zsh
의 경우 ksh
중괄호 확장(예: a{b,c}
가 ab
및 ) 도 수행합니다.ac
기본값에는 $IFS
SPC, TAB 및 NL 문자가 포함됩니다( zsh
다른 쉘에서는 NUL을 제거하거나 종료합니다). 이것들(NUL 아님)은 IFS 공백 문자이기도 하며 IFS 분할 중에 특별히 처리됩니다.
Split+glob 연산자는 의 출력이 이고 cmd
인수 가 이면 생성 됩니다 . IFS 공백 문자의 경우 하나 이상의 IFS 공백 문자 시퀀스가 고려되므로 빈 인수를 생성 할 수 없습니다." a b\nc \n"
"a"
"b"
"c"
./input
split+glob
하나분리 기호. 빈 매개변수를 생성하려면 IFS 공백 문자가 아닌 구분 기호를 선택해야 합니다. 실제로 공백이 아닌 문자는 모두 가능합니다(모든 쉘이 지원하는 것은 아니지만 멀티바이트 문자를 피하는 것이 가장 좋습니다).
예를 들어, 다음과 같은 경우:
IFS=: # split on ":" which is not an IFS-whitespace character
set -o noglob # disable globbing (also brace expansion in ksh)
./input $(cmd)
cmd
출력 인 경우 a::b\n
분할+glob 연산자는 및 인수를 생성합니다 "a"
( ""
s "b"
는 "
값의 일부가 아니며 여기서는 값을 표시하는 데 도움이 되도록 사용하고 있습니다).
의 경우 a:b:\n
셸에 따라 "a"
and "b"
또는 "a"
, "b"
and 가 됩니다 ""
. 다음 명령을 사용하여 모든 셸에서 일관성을 유지할 수 있습니다.
./input $(cmd)""
(이는 빈 출력 cmd
(또는 개행만 포함하는 출력) 의 경우 ./input
인수가 전혀 없는 대신 빈 인수가 수신된다는 의미이기도 합니다.
예:
cmd() {
printf 'a b:: c\n'
}
input() {
printf 'I got %d arguments:\n' "$#"
[ "$#" -eq 0 ] || printf ' - <%s>\n' "$@"
}
IFS=:
set -o noglob
input $(cmd)
다음을 제공합니다:
I got 3 arguments:
- <a b>
- <>
- < c>
또한 이 작업을 수행할 때 다음 사항에 유의하세요.
./input ""
이는 "
쉘 구문의 일부이며 쉘 인용 연산자입니다. 이러한 "
문자는 에 전달되지 않습니다 input
.
^IFS 공백 문자, 각 POSIX는 로케일로 분류된 문자 이며 ksh88(POSIX 사양의 기반) 및 대부분의 셸에서 [:space:]
발생하는 것처럼 이는 여전히 SPC, TAB 및 NL로 제한됩니다. $IFS
이와 관련하여 제가 찾은 유일한 POSIX 호환 셸은 입니다 yash
. ksh93
( bash
5.0 기준) 다른 공백(예: CR, FF, VT...)도 포함하지만 단일 바이트 공백으로 제한됩니다(예: Solaris)(일부 영역에는 단일 바이트의 잘림 방지 공백이 포함됨)
답변2
프로그래밍 방식으로 전체 명령줄을 생성한 다음 복사하여 붙여넣거나 eval을 통해 실행할 수 있습니다. 예를 들면 다음과 같습니다.
$ perl -e 'printf "./args.sh %s\n", q/"" / x 10'
./args.sh "" "" "" "" "" "" "" "" "" ""
$ eval "$(perl -e 'printf "./args.sh %s\n", q/"" / x 100')"
$#: 100
$1: ><
( 이것은 수백 개의 복사본을 만들고 연결하여 q/"" /
Perl이 문자열을 인용하는 방법 중 하나입니다 .)x 100
eval
해당 인수를 셸 명령으로 처리하여 모든 인용 처리 및 확장을 실행합니다. 이는 입력이 신뢰할 수 없는 소스에서 오는 경우 취약성을 방지하기 위해 평가 코드를 생성할 때 주의해야 함을 의미합니다.
빈 인수 변수의 수를 원하면 문제가 되지 않습니다. (적어도 Perl의 두 번째 피연산자가 x
피연산자를 정수로 축소하기 때문에 어떻게 잘못 사용될 수 있는지 알 수 없습니다.)
$ n=33
$ eval "$(perl -e 'printf "./args.sh %s\n", q/"" / x $ARGV[0]' "$n")"
$#: 33
$1: ><
답변3
그런데 실제로 무엇을 극복하려고 합니까? 비어 있는인용 부호또는 비어 있음끈? 둘 다 유효한 매개변수입니다. 이 간단한 bash 스크립트는 이를 설명하는 데 도움이 될 수 있습니다.
#!/bin/bash
printf "Argument count: %s.\n" "${#@}"
전달된 인수의 수만 인쇄합니다. s
편의상 이라고 부르겠습니다.
$ ./s a
Argument count: 1.
$ ./s a b
Argument count: 2.
$ ./s a b ""
Argument count: 3.
$ ./s a b "" ""
Argument count: 4.
$ ./s a b "" "" \"\"
Argument count: 5.
보시다시피, 빈 문자열은 단지 빈 문자열입니다. 구문 분석 시 따옴표가 제거되며 여전히 유효한 인수입니다. 쉘은 이를 명령에 입력합니다. 그러나 ""
그것은 또한 전달될 수도 있다. 하지만 빈 문자열은 아닙니다. 두 개의 문자가 포함되어 있습니다.
내부적으로 C에서는 문자열이 NUL( \0
)로 끝나며 문자열을 표시하는 데 따옴표가 필요하지 않습니다.