'
(다른 문자도 가능) 변수에 유지할 수 없으므로 Bash 함수/스크립트 인수를 변수에 완전히 복사하려면 어떻게 해야 합니까 ?
예를 들어
m() {
v="$@"
echo "$v"
}
$ m let it be 'foo' bar
let it be foo bar
진심으로 도움을 주셔서 감사합니다. 미리 감사드립니다.
답변1
여기서 주목해야 할 점은 예를 들어 실행할 때입니다.
m let it be 'foo bar'
프로그램은 m
전체 명령줄을 가져오지 않지만 쉘은 먼저 명령줄을 구문 분석하여 따옴표, 변수 확장 등을 처리합니다. 이 명령의 최종 결과는 개별 문자열의 배열과 비슷합니다(이 경우 [ let
, it
, be
, foo bar
]).
마찬가지로,
f="James Matthew"
l="Bond"
m "$l, $f $l"
m
[ ]만 Bond, James Matthew Bond
보이고 관련된 변수와 따옴표는 알 수 없습니다.
이는 일반 프로그램이 원래 입력 라인에 접근할 수 없음을 의미합니다.
zsh에는 사전 실행 핸들러에 대한 솔루션이 있습니다이스케이프나 인용 없이 확장된 쉘을 닫을 수 있는 방법이 있습니까?그리고zsh: 쉘 제어 문자를 포함하여 명령줄만 반향하는 별칭 또는 쉘 함수, 하지만 Bash를 본 적이 없는 것 같습니다.
가장 가까운 것은 DEBUG
확장, 참조 처리 및 리디렉션 전에 실행될 명령을 보는 트랩입니다. 하지만 한 번에 하나의 간단한 명령만 보기 때문에 완전하지 않습니다. 주석은 표시되기 전에 제거되며, 인용되지 않은 ;
, &
, |
, &&
, ||
또는 (
( )
적어도) 주석은 계속 구문 분석됩니다.
어쨌든, 우리는 다음을 시도해 볼 수 있습니다:
#!/bin/bash
shopt -s extdebug
handle_@ () {
local re='[[:space:]]*@ ([^[:space:]]+)[[:space:]]+(.*)'
if [[ $BASH_COMMAND =~ $re ]]; then
"${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
return 1
fi
}
m() {
printf "<%s>\n" "$1"
}
trap handle_@ DEBUG
@ m 'foo bar' doo "$var" > /dev/null
@ m what about this?; date
@ m or some (parentheses)?
스크립트는 DEBUG
트랩을 사용하여 로 시작하는 명령을 감지하고 @
공백으로 구분된 다음 "단어"를 실행할 명령으로 사용하고 나머지를 단일 인수로 전달합니다. 트랩 처리기에서 돌아오면 1
쉘이 실제로 명령을 일반적인 방법으로 실행하지 않도록 지시하므로 오류 메시지가 발생하지 않고 포함된 확장이 실행되지 않습니다( extdebug
설정이 필요함).
출력은 다음과 같으며, date
그 뒤에 세미콜론이 있고 괄호가 구문을 깨뜨린다는 것을 보여줍니다.
<'foo bar' doo "$var" > /dev/null>
<what about this?>
Sun Sep 18 18:39:38 EEST 2022
debugprint.sh: line 20: syntax error near unexpected token `('
debugprint.sh: line 20: `@ m or some (parentheses)?'
솔직히 말하면 조금 역겹고, 특수 문자에 대한 제한은 꽤 임의적이며, 스크립트에 다른 문제가 없을 것이라고 보장할 수 없습니다.
일반적으로 이것을 일종의 프로덕션 용도로 사용할 계획이라면 프로그램 구조를 다시 생각하고 수행 중인 작업에 따라 파일이나 예를 들어 여기 문서를 통해 문자열을 가져오는 것이 좋습니다.
여기에 있는 문서에서는 다음 명령을 사용하지만 원시 문자열을 비교적 쉽게 입력할 수 있습니다 stdin
.
m() {
m=$(cat)
printf "<%s>\n" "$m"
}
m <<'EOF'
Say "$hello" to my 'little friend'
EOF
그런 다음 인쇄
<Say "$hello" to my 'little friend'>
here-doc로 구분된 문자열(in <<'EOF'
)을 사용하면 따옴표 걱정 없이 임의의 텍스트와 문자를 넣을 수 있습니다. (물론 구분자 문자열 자체를 제외하고 대신 무작위로 생성된 문자열을 사용할 수 있습니다 EOF
.)
답변2
다음과 같이 작은따옴표가 변수 값의 일부라고 셸이 믿도록 해야 합니다.
m let it be "'foo'" bar
답변3
쉘은 '
함수가 따옴표를 보기 전에 따옴표를 해석하고 "
예를 들어 및 에 대해 동일한 작업을 수행합니다 \
. 예를 들어 를 사용하여 이스케이프할 수 있습니다 \
.
$ m let it be \'foo\' bar
let it be 'foo' bar
and
$ m let it be \"foo\" bar, \' \\ \"$foo\" \"\$foo\"
let it be "foo" bar, ' \ "" "$foo"
답변4
여기서 문제는 따옴표 없이 입력을 전달한다는 것입니다. 결과적으로 '
쉘에 의해 소비됩니다.앞으로함수를 호출하세요. 를 사용하는 경우에도 동일한 일이 발생하며, "
또는 와 같은 와일드카드를 사용하는 경우에도 실패합니다.*
?
$ ls
file1 file2
$ m "aa"bb
aabb
$ m f*2
file2
적어도 나에게 가장 깨끗한 해결책은 항상 인용된 입력을 전달하는 것입니다. 이렇게 하면 셸에서 특별한 의미를 갖는 모든 문자가 보호되어 해당 문자가 변경되지 않고 함수에 전달됩니다.
$ m '"aa"bb'
"aa"bb
$ m "foo 'bar' baz"
foo 'bar' baz
$ m "f*2"
f*2