Bash:スペースと引用符付きの文字列を配列に変換する

Bash:スペースと引用符付きの文字列を配列に変換する

引用符の中に一連の文字列を出力する関数(私が作成したものではありません)があります。

command <args>

“Foo”
“FooBar”
“Foo Bar”
“FooBar/Foo Bar”

配列(Bash、BSD / Mac)に割り当てようとすると、4つではなく7つの要素が表示されます。たとえば、${array[2]}私にしなければならないgetですが、代わりに“Foo Bar”私が取得する”Foo次の要素はBar”.any要素です。いいえスペースはうまく機能します(例${array[0]}:「Foo」)

要素自体が空白(?)で区切られた配列に引用符(スペースを含む)間の各要素を割り当てる方法は?

私はsed / awkを使って引用符を「削除」することを考えていますが、より良い効率的な方法が必要だと思います。

現在、私はコマンドの出力(引用符を含む上記の出力とまったく同じです)を一時変数に割り当て、それを配列に割り当てます。

_tempvar=“$(command <args>)”

declare -a _array=(${_tempvar})

答え1

では、ファイルの行や一部のコマンドの出力を配列として読み取るbashことができます。readarrayただ この機能は2009年にリリースされたバージョン4.0に追加されましたが、macOSにはまだbash 3.2が付属しています。

macosはzshに付属していますが、これはより良いシェルです。

空でないコマンド出力行を取得するには、引数拡張fフラグを使用して分割しf(eed行で分割)、演算子記号を使用して"(U + 0022)、(U + 0201C)、および(U + 201D)文字を削除できます。 。${var//pattern[/replacement]}のような:

#! /bin/zsh -
array=( ${(f)${"$(cmd)"//['"“”']}} ) || exit

U + 0022 ASCII文字で引用された文字列で、引用符が言語で引用符がどのように機能するかと互換性がある場合は、/フラグ(言語パーサーと同じ方法でテキストを表示するため)とフラグを使用することもzshできます。 (引用符を削除するために)1行に分割する代わりに(引用符付きの文字列を複数行に渡すことはできません)zZQ

#! /bin/zsh -
array=( ${(Q)${(Z[n])"$(cmd)"}} ) || exit

あなたの

declare -a array=(${tempvar})

inは、bash引用符なしで(通常は意図せずに)拡張されたときに呼び出される分割+glob演算子を使用します。複雑なアルゴリズムを使用して、出力を$IFS特殊パラメータの文字(bashではデフォルトでは空白、タブ、および改行文字を含む)に分割し、結果の単語は次のようになります。ワイルドカードまた〜として知られていますファイル名の生成(これはほとんど望ましくありません)。

ここでは、分割+globを使用してコマンド出力の空でない行を取得できますが、まずそれを調整する必要があります。

IFS=$'\n' # split on newline only:
set -o noglob # disable the glob part which we don't want
array=( $(cmd) ) # split+glob

"“”その後、withを削除することもできますが、${var//pattern[/replacement]}bashでは引数拡散演算子を蓄積できず、構文(ksh93から継承されます)が少しぎこちないため、後で行う必要があります。

array=( "${array[@]//['"“”']}" )

この方法とは異なり、zsh次の操作は処理されません"foo \"bar\" and \\backslash"

答え2

スペースによってトークン化が発生するため、7つの要素を取得します。

IFS=$'\n'文字列を配列に追加する前に設定すると、4つの要素が表示されますが、二重引用符が含まれます。

例:

IFS=$'\n'

arr=($(command <args>))

引用符なしで4つの要素が必要な場合は、次のようにします。

IFS=$'\n'

arr=($(command <args> | sed s'#"##'g))

完全な例:

IFS=$'\n'

# tst.txt has your strings:
arr=($(cat tst.txt | sed s'#"##'g))

declare -p arr

出力:

declare -a arr=([0]="Foo" [1]="FooBar" [2]="Foo Bar" [3]="FooBar/Foo Bar")

答え3

readarray -t array <<< $(echo $'"a a"\n"b   b"\n"c   c"')
declare -p array
declare -a array=([0]="\"a a\"" [1]="\"b   b\"" [2]="\"c   c\"")
readarray -t array <<< $(command <args>)

関連情報