간단한 bash 파서를 작성하려고 합니다. 나는 이 단계를 따르고 있습니다위키피디아. 제가 가정한 것 중 하나는 문자를 올바르게 이스케이프 처리하면 전체 입력 문자열을 반복하여 작은따옴표와 큰따옴표를 모두 제거할 수 있다는 것이었습니다. Bash에서 실행하면 이 두 문자열은 동일한 출력을 생성해야 합니다.
내 파서의 이 부분은 주어진 문자열을 가져와서 작은 따옴표와 큰 따옴표를 제거합니다(이스케이프되어 리터럴로 해석되는 따옴표는 제외). Bash에서 실행하면 두 문자열 모두 여전히 동일한 결과를 생성해야 합니다.
내 파서는 아래와 같이 원시 콘텐츠를 내 파서로 변환합니다. 그러나 원본은 작동하지만 My Parse는 작동하지 않습니다.
# Original
$ node -p "console.log($(echo \"hello world\"))"
hello world
# My Parse: Escape everything within double quotes except command substitution
v v
$ node -p \c\o\n\s\o\l\e\.\l\o\g\($(echo \"hello world\")\)
[eval]:1
console.log("hello
^^^^^^
SyntaxError: Invalid or unexpected token
구문 분석 오류의 원인에 대해 몇 가지 아이디어가 있습니다.
큰따옴표 내의 명령 대체가 작동하는 방식에 대한 몇 가지 기본 측면을 이해하지 못합니다. 내 이해는 명령 대체가 먼저 발생한 다음 따옴표가 처리된다는 것입니다.
명령 대체가 실제로 어떻게 출력되는지에 대한 몇 가지 기본적인 측면을 이해하지 못합니다. 내 이해는 명령이 아닌
$(echo \"hello world\")
문자열을 생성해야 한다는 것입니다 ."hello world"
"hello
world"
이 명령에는 몇 가지 특징이 있습니다
echo
(아마 변경 가능하기 때문일 것입니다). 실제로 운이 좋아서 원래 시나리오에서는 작동했지만 실제로는 명령 대체에서 명령을 변경하면 문제가 발생할 수 있습니다.노드/자바스크립트에 문제가 있습니다. 이것은 매우 간단한 js이므로 그게 전부라고 생각하지 않습니다 ...
마지막으로 흥미로운 점은 명령 대체를 큰따옴표로 묶을 때 작동한다는 것입니다. 어쩌면 전체 질문을 다르게 물어볼 수도 있습니다. 큰따옴표(이스케이프된 부분은 포함하지 않음) 없이 아래와 동일한 입력을 어떻게 작성할 수 있습니까?
# Escape everything but keep command substitution in double quotes
v v
$ node -p \c\o\n\s\o\l\e\.\l\o\g\("$(echo \"hello world\")"\)
hello world
참고: 이 질문은 약간의 후속 질문입니다.큰따옴표 이스케이프에 관한 이 질문
답변1
이것은분사행동 중. 시작하기 전에 주의 깊게 읽어주세요.쉘 확장실행되는 순서에 주의하세요.
보고 있다node -p "console.log($(echo \"hello world\"))"
확장을 지원하나요? 아니요
물결표 확장? 아니요
매개변수 확장? 여기가 아니야
명령 대체? 응, 맡겨만 둬
node -p "console.log("hello world")"
산술 확장? 아니요
프로세스 교체? 아니요
분사? 매개변수는
-p
따옴표로 묶여 있으므로 그렇지 않습니다.파일 이름 확장자? 아니요
견적 삭제 완료
node
bash는 2개의 매개변수를 생성 하고 전달합니다 -p
.console.log("hello world")
지금 봐node -p console.log($(echo \"hello world\"))
명령 대체 후, 우리는
node -p console.log("hello world")
단어 분할을 수행할 때 to 인수에는
-p
이를 보호할 따옴표가 없습니다. 현재 명령의 경우 bash에는 4개의 플래그가 있습니다.node -p console.log("hello world") ^^^^ ^^ ^^^^^^^^^^^^^^^^^^ ^^^^^^^
bash는 node
이를 통해 생성됩니다.삼인수: -p
및 --는 분명히 자바스크립트 구문 오류입니다 console.log("hello
. 무슨 일이 일어나는지 보게 될 것입니다.world")
console.log("hello
자세한 내용은 다음을 참조하세요.bash/POSIX 쉘에서 변수를 인용하는 것을 잊어버리는 보안 위험
답변2
귀하의 예에서 "node -p"가 무엇을 해야 하는지 모르겠습니다. 그러나 예제를 재현하려고 하면 다음과 같은 결과가 발생합니다.
[user@c0n1 ~]# echo "hello world"
hello world
[user@c0n1 ~]# echo $(\"hello world\")
-bash: "hello: command not found
마지막 예의 공백은 따옴표 안의 문자열을 분리하고 &bash는 "hello"가 명령이라고 생각합니다. 백슬래시로 공백을 보호하면 다음 설명이 확인됩니다.
[user@c0n1 ~]# echo $(\"hello\ world\")
-bash: "hello world": command not found
명령 대체에서 문자열을 생성하려는 경우 다음과 같은 명령이 필요합니다.
[user@c0n1 ~]# echo $(echo \"hello world\")
"hello world"
답변3
답안지:@glen-jackman의 답변은 훌륭하고 저에게 영감을 주었습니다.
내 bash 스크립트는 다음과 같습니다.
cmds="git commit -m \"$(date)\""
echo $cmds
$cmds
스크립트를 실행하면 다음과 같은 결과가 나타납니다.
git commit -m "Fri Jan 13 10:27:05 CST 2023"
error: pathspec 'Jan' did not match any file(s) known to git
error: pathspec '13' did not match any file(s) known to git
error: pathspec '10:27:05' did not match any file(s) known to git
error: pathspec 'CST' did not match any file(s) known to git
error: pathspec '2023"' did not match any file(s) known to git
set -x
스크립트를 디버깅하기 위해 다음을 얻었습니다.
++ date
+ cmds='git commit -m "Fri Jan 13 10:34:30 CST 2023"'
+ echo git commit -m '"Fri' Jan 13 10:34:30 CST '2023"'
git commit -m "Fri Jan 13 10:34:30 CST 2023"
+ git commit -m '"Fri' Jan 13 10:34:30 CST '2023"'
error: pathspec 'Jan' did not match any file(s) known to git
error: pathspec '13' did not match any file(s) known to git
error: pathspec '10:34:30' did not match any file(s) known to git
error: pathspec 'CST' did not match any file(s) known to git
error: pathspec '2023"' did not match any file(s) known to git
실제로 실행할 명령은 다음과 같습니다.git commit -m '"금요일' 1월 13일 10:34:30 CST '2023"'하지만 내가 기대하는 것은git commit -m "2023년 1월 13일 금요일 10:34:30 CST".
이것은분사행동 중
eval
내 솔루션은 다음과 같이 수정된 스크립트를 사용하는 것이었습니다 .
cmds="git commit -m \"$(date)\""
echo $cmds
eval $cmds
작동하며 출력은 다음과 같습니다.
++ date
+ cmds='git commit -m "Fri Jan 13 10:43:56 CST 2023"'
+ echo git commit -m '"Fri' Jan 13 10:43:56 CST '2023"'
git commit -m "Fri Jan 13 10:43:56 CST 2023"
+ eval git commit -m '"Fri' Jan 13 10:43:56 CST '2023"'
++ git commit -m 'Fri Jan 13 10:43:56 CST 2023'
[main b76daa9] Fri Jan 13 10:43:56 CST 2023
2 files changed, 21 insertions(+), 22 deletions(-)