ある変数の特定の行を別の変数に割り当てる

ある変数の特定の行を別の変数に割り当てる

ある変数から別の変数に特定の行を転送したいと思います。私はこれを試しましたが、うまくいきません。

c="1.apple
2.banna
3.peach"

read "Please choose fruit [1-3]:" t

a=$c | awk "NR==$t"
echo "You choose: $a"

私の間違いは何ですか?

答え1

答え2

最初:

read "Please choose fruit [1-3]:" t

...動作しません。 shellbuildinにプロンプ​​ト文字列を提供したいようですが、readオプションreadが指定されていない限り、最初の引数を変数名として解釈してstdinから読み取られた行の値を割り当てます。

read -p "Please choose fruit [1-3]:" t

... は多くのシェルでサポートされているオプションで、必要な操作に近いものです。

つまり、以前に値をどのように分割するかを特定していない限り、単一の区分割り当てに複数の値を重ねてはいけません。これを行うとき:

var=' some list of things '

シェルは最終的にこれを次のように解析します。

\0 some list of things \0

...単一の値に単一の名前を割り当てます。多くのシェルは、名前付き配列などの高度な型の分離を提供しますが、すべてのPOSIXシェルは、関数コンテキストで$@簡単に定義できる少なくとも1つの配列、つまりシェル配列を提供します。名前付き配列を提供するさまざまな実装は、名前付き配列に対するシェル配列の$@動作を模倣することがよくあります。

したがって、次のようにこれらすべての個別の値を単一の文字列に割り当てる代わりに、

set apple banana peach

次のように、個々の値を数値として個別に処理して効果を確認できます。

printf %s\\n "$1"

...印刷:

apple

注 – 9 より大きい値を使用するには、参照を中かっこで囲むことをお勧めします。"${10}"

次のように一意の文字列数を確認できます"$#"

printf %d\\n "$#"

...印刷...

3

別々の文字列リストでこれらの問題の多くを解決することができます。たとえば、次のようになります。

printf %s\\n "$@"

...印刷:

apple
banana
peach

...または単一の接続文字列として使用されます。たとえば、次のようになります。

printf %s\\n "$*"

...ここで、個々の配列値文字列はシェル変数に含まれる最初の文字に連結されます$IFS。したがって、配列の各文字列にデフォルト値がある場合は、$IFSその間に単一の文字列を使用して次の文字列に連結されます。たとえば、上記のコマンドは以下を印刷します。<space><tab><newline><space>

apple banana peach

...しかし、そうするなら:

IFS='fruit sucks'; printf %s\\n "$*"

...次のように印刷されます。

applefbananafpeach

名前付き配列拡張を実装するほとんどのシェルは同様の構文を使用しますが、配列アドレスを指定するさまざまな方法は名前に関連付ける必要があります。配列の割り当ては通常次のとおりです。

array=( apple banana peach )

...または...

array[0]=apple array[1]=banana array[2]=peach

"$1"名前付き配列は通常、、、"$#""$@"比較して機能し、前述のものとの間の関係は引き続き適用されます。"$*""${array[1]}""${#array[@]}""${array[@]}""${array[*]}""$*""$IFS""${array[*]}"

価値観を正しく定義すると、問題の処理が容易になります。

set apple banana peach; n=0
{   for a do printf "$((n+=1)).:\t%s\n" "$a"; done
    printf "Please choose fruit [1-$#]: "; read t
} <>/dev/tty >&0 &&
[ "0$((!${#t}))" -lt "0${t##*[!0-9]*}" ] &&
eval 'printf "You choose: %s\n" "${'"$t"}\"

いくつかは上記の使用を嘲笑するかもしれませんが、evalここで使用することは多くの人が望むものよりも安全ではありません。"${array[$t]}" (名前付き配列を使用してこれを行う1つの方法は次のとおりです。)なぜなら、最初に文字列に解析した後、"${array[$t]}"2番目に評価されるという意味だからです。$t少なくとも1と数字だけが含まれていて、0より大きいことを確認するために上記のようにテストする必要はありません。(または最小の名前付き配列インデックスのシェル実装は何ですか)いずれの状況でも予期しない結果が生じる可能性があります。

関連情報