シェルスクリプトで引用された引数リスト文字列を正しく解析する方法は?

シェルスクリプトで引用された引数リスト文字列を正しく解析する方法は?
一般化する

a "b" 'c d' $'e\nf'引用符を尊重し、スペースと改行文字を保持しながら、単一の文字列を別々のパラメータに変換する方法は?

質問

値のリスト(1行に1つずつ)を引用符付きの文字列(で生成)にエクスポートするスクリプトの出力を読み取り、処理しようとしていますprintf %q。リストの値はスペースで区切られ、引用符で囲むことができ、スペースと改行を含めることができ、数を知ることができません。

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

POSIXシェルスクリプトから値を復元し、それをシェル関数の引数として扱う方法を探しています。

必要なソリューション(優先順位の降順):

  1. POSIXシェルコマンドとコアユーティリティxargsなどprintfeval
  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

おすすめ記事