올바른 따옴표를 사용하여 스크립트 파일에 명령 쓰기

올바른 따옴표를 사용하여 스크립트 파일에 명령 쓰기

나는 상황에 몇 번 부딪혔습니다. 몇 가지 설정을 수행한 다음 다음과 같이 다소 임의적인 명령을 호출하는 쉘 함수가 있습니다.

setup_and_run() {
    some_setup_commands
    "$@"
}

동일한 설정을 완료한 후 명령을 다시 실행하는 데 사용할 수 있는 스크립트 파일을 작성하도록 이 함수를 변경하고 싶습니다. 다음을 수행할 수 있습니다. 이는 명령에 공백이나 기타 이상한 내용이 포함된 인수가 없을 때 작동합니다.

setup_and_run() {
    some_setup_commands
    cat >>rerun.sh <<EOF
some_setup_commands
$@
EOF
    "$@"
}

일부 매개변수에 공백이나 기타 특수 문자가 있는 경우에도 일반적으로 스크립트를 올바른 따옴표로 작성할 수 있도록 이를 변경하는 표준 방법이 있습니까?

예를 들어, 의 두 번째 정의에 대해 다음을 setup_and_run실행하면

$ setup_and_run ls "my cat's \"password\""
my cat's "password"

그러면 다음 rerun.sh이 포함됩니다

some_setup_commands
ls my cat's "password"

그리고 나는 그것이 다음과 같은 것을 포함하고 싶습니다

some_setup_commands
ls "my cat's \"password\""

또는

some_setup_commands
ls my\ cat\'s\ \"password\"

또는 그런 것.

상황이 급하면 Python과 같은 서비스에 아웃소싱할 수도 있습니다.shlex.quote(), 그러나 가능하다면 쉘 자체에서 수행할 수 있거나 최소한 경량의 표준 UNIX 도구를 사용하여 수행할 수 있는 작업을 찾고 있습니다.

답변1

%qBash, ksh93 및 zsh에서는 이스케이프 문자를 사용할 수 있습니다printf내장.

#!/bin/bash
# also works in ksh93, zsh
setup_and_run() {
    some_setup_commands
    cat >>rerun.sh <<EOF
some_setup_commands
$(printf '%q ' "$@")
EOF
    "$@"
}

printf -vBash에서는 표준 출력 대신 변수에 출력을 쓰는 데 사용할 수 있습니다 .

#!/bin/bash
printf -v cmd '%q ' "$@"
setup_and_run() {
    some_setup_commands
    cat >>rerun.sh <<EOF
some_setup_commands
$cmd
EOF
    "$@"
}

zsh에는 다른 접근 방식이 있습니다.q 매개변수 확장 플래그, 그 뒤에 j: :배열 요소를 연결하는 공백이 옵니다.

#!/bin/zsh
setup_and_run() {
    some_setup_commands
    cat >>rerun.sh <<EOF
some_setup_commands
${(j: :)${(q)@}}
EOF
    "$@"
}

일반 sh에서는 이것이 더 어렵습니다. 단어를 인용하는 신뢰할 수 있는 방법은 단어를 작은따옴표로 묶고 그 안의 각 작은따옴표를 바꾸는 것입니다 '\''. 올바른 대체를 얻는 것은 쉽지 않으며 sed 또는 루프에 대한 외부 호출이 필요합니다.

#!/bin/sh
quote_simple_command () {
  quoted=
  for raw in "$@"; do
    quoted="$quoted'"
    while case "$raw" in *\'*) true;; *) false;; esac; do
      quoted="$quoted${raw%%\'*}'\\''"
      raw="${raw#*\'}"
    done
    quoted="$quoted$raw' "
  done
  printf %s "${quoted% }"
}
setup_and_run() {
    some_setup_commands
    cat >>rerun.sh <<EOF
some_setup_commands
$(quote_simple_command "$@")
EOF
    "$@"
}

관련 정보