Q1:実行時にユーザー入力として配列項目を取得し、項目を印刷し、配列の長さを印刷したいと思います。これが私が持っているものです:
read -a myarray
echo "array items" ${myarray[@]}
echo "array length" ${#myarray[@]}
実行中に、以下を入力として提供しました。
$ ("apple fruit" "orange" "grapes")
出力は、
array items "apple fruit" "orange" "grapes"
array length 4
これは正確ではありません。
ユーザー入力を要求せずにコードの一部として宣言され、初期化された配列を使用すると、配列のmyarray=("apple fruit" "orange" "grapes")
長さは3にエコーされます。だから読み取りコマンドを誤って使用しているようです。
質問2:以下のように読み取りコマンドにプロンプトを追加すると、
read -p "enter array items: " myarray
最初のアイテム「リンゴの果実」が「果物」として印刷され、長さも間違っています。
プロンプトを削除して-aを追加すると、すべてが正常です。 aとpを組み合わせてread -apと指定すると、プロンプトはまったく表示されません。値を待ちますが、メッセージはありません。なぜですか?誰かが私に何が間違っているかを説明できますか?
答え1
質問1:
あなたの例では、read
入力はコマンドライン引数ではなく標準入力から取得されます。したがって、受信した入力はbash
文字列パーサーを通過しません。代わりに、スペースで区切られたリテラル文字列として扱われます。したがって、入力に応じて配列値は次のようになります。
[0]->("apple
[1]->fruit"
[2]->"orange"
[3]->"grapes"
必要な操作を実行するには、区切り文字が適用されないようにすべてのスペースをエスケープする必要があります。つまり、呼び出し後に次のように入力する必要がありますread
。
apple\ fruit oranges grapes
read
Q2:受信した入力を配列として保存するには、-a
スイッチの後に配列名を付ける必要があります。したがって、以下が必要です。
read -a myarray -p "Enter your items"
答え2
シェルのコマンドラインパーサーは二重引用符と一重引用符に興味がありますが、そうではありませんread
(したがって、どちらも削除しません)。入力するにはread
バックスラッシュが必要です。
apple\ fruit orange grapes
答え3
ユーザーが要素を区切るためにシェル引用符を使用するようにするには、backslash
次zsh
のようにします。
IFS= read -r 'string?Please enter the elements: '
array=("${(@XQ)${(z)string}}")
(z)
$string
これはシェルパーサなどの要素に分割されます。Q
結果の単語から最初のレベル参照を削除します。X
構文によるエラーメッセージの報告@
空の要素を保存するには、引用符を使用してください。
このようにして、ユーザーは次のように入力できます。
'first word' "second word" third\ word $'word\nwith\nnewline' ''
拡張が行われなくても、予想されるシェルコード構文は引用符に限定されません。たとえば、単一の単語$(foo bar)
に解析され、構文エラーが発生します。ユーザーはこれを、または「${unknown」と入力する必要があります。$(foo bar)
${unclosed
'$(foo)' 'bar)'