쉘 스크립트에서 인용된 인수 목록 문자열을 올바르게 구문 분석하는 방법은 무엇입니까?

쉘 스크립트에서 인용된 인수 목록 문자열을 올바르게 구문 분석하는 방법은 무엇입니까?
일반화하다

a "b" 'c d' $'e\nf'따옴표를 존중하고 공백과 개행 문자를 유지하면서 단일 문자열을 별도의 매개변수로 변환하는 방법은 무엇입니까 ?

질문

값 목록(한 줄에 하나씩)을 따옴표 붙은 문자열(에서 생성)로 내보내는 스크립트의 출력을 읽고 처리하려고 합니다 printf %q. 목록의 값은 공백으로 구분되고, 따옴표로 묶을 수 있으며, 공백과 줄 바꿈을 포함할 수 있으며 개수를 알 수 없습니다.

예:a "b" 'c d' $'e\nf'

POSIX 쉘 스크립트에서 값을 복원하고 이를 쉘 함수에 대한 인수로 처리하는 방법을 찾고 있습니다.

필요한 솔루션(우선순위 내림차순):

  1. POSIX 쉘 명령 및 핵심 유틸리티 xargsprintfeval
  2. 불다
  3. Perl과 같은 성숙한 프로그래밍 언어
쉘 스크립트의 뼈대 process.sh:
#!/bin/sh
set -eu

process() {
  printf '>%s<\n' "${@}"
}

main() {
  value_list="${1}"
  # split value list here and set positional parameters
  set -- ???
  process "${@}"
}

main "${@}"
원하는 행동
$ process.sh "a \"b\" 'c d' $'e\nf'"
>a<
>b<
>c d<
>e
f<
지금까지 무슨 일이 있었나요
  • printf나는 (포함 %q), xargs루프 while read, 변경 IFS, 바이트 구분 인수 null, 서브쉘 호출, heredocs 의 다양한 조합을 시도했습니다 .
  • xargs역참조는 허용되지만 공백에 대해서만 가능하고 개행 문자에는 허용되지 않으며 인수 없이만 허용됩니다 -d.
  • 루프는 while read인수를 구문 분석할 수 있지만 파이프에서 입력을 읽는 동안 셸 함수를 호출하는 것은 허용되지 않습니다.

답변1

이 답변은 다음을 기반으로 합니다.논평통과이르카초을 사용하고 zsh.

쉘 스크립트 process.sh:
#!/bin/sh
set -eu
export script="$(readlink -f "${0}")"

split() {
  zsh -c 'printf "%s\0" "${(Q@)${(z)1}}"' "${script}/split" "${@}"
}

process() {
  printf '>%s<\n' "${@}"
}

main() {
  value_list="${1}"
  split "${value_list}" | xargs -0 sh -c 'init() { . "${script}"; } && init && process "${@}"' "${script}/main"
}

[ "${#}" -eq 0 ] || main "${@}"
혜택
  • 효과가있다
결점
  • 매개변수를 제거하고 무한 루프를 방지하기 위해 process()양식을 호출하는 스크립트를 함수로 래핑해야 하는 것은 약간 어색합니다.xargs
  • 필요하다zsh

답변2

단순화된 변형이것 zsh다음을 기준으로 답변하세요.

#!/bin/zsh
set -eu

process() {
  printf '>%s<\n' "${@}"
}

main() {
  value_list="${1}"
  process "${(Q@)${(z)value_list}}"
}

main "${@}"
혜택
  • 효과가있다
결점
  • zsh 요구 사항

관련 정보