명령 대체에서 큰따옴표를 이스케이프하세요

명령 대체에서 큰따옴표를 이스케이프하세요

간단한 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

구문 분석 오류의 원인에 대해 몇 가지 아이디어가 있습니다.

  1. 큰따옴표 내의 명령 대체가 작동하는 방식에 대한 몇 가지 기본 측면을 이해하지 못합니다. 내 이해는 명령 대체가 먼저 발생한 다음 따옴표가 처리된다는 것입니다.

  2. 명령 대체가 실제로 어떻게 출력되는지에 대한 몇 가지 기본적인 측면을 이해하지 못합니다. 내 이해는 명령이 아닌 $(echo \"hello world\")문자열을 생성해야 한다는 것입니다 ."hello world""helloworld"

  3. 이 명령에는 몇 가지 특징이 있습니다 echo(아마 변경 가능하기 때문일 것입니다). 실제로 운이 좋아서 원래 시나리오에서는 작동했지만 실제로는 명령 대체에서 명령을 변경하면 문제가 발생할 수 있습니다.

  4. 노드/자바스크립트에 문제가 있습니다. 이것은 매우 간단한 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따옴표로 묶여 있으므로 그렇지 않습니다.

  • 파일 이름 확장자? 아니요

  • 견적 삭제 완료

nodebash는 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(-)

관련 정보