質問し、答えが空であることを確認する一般的な関数を作成します。

質問し、答えが空であることを確認する一般的な関数を作成します。

私は多くの問題を解決するシェルアプリケーションを作成しており、これを何度も使用してきread -p "<my_question>" <myvar>ました。問題は、答えが空であることを確認したいということです。だから私は空であるかどうかを尋ねて確認する一般的な関数を作成したいと思います。その場合、ユーザーが何かを提供するまで関数自体が再帰的に呼び出されます。変数名を「userdatabase」に「変更」すると、すべてが完全に実行されます。関数宣言と使用法に従ってください。

ask() {
    read -p "$1" $2

    if [[ -z $userdatabase ]]; then
        echo Empty is not allowed
        ask "$1" $2
    else
        echo $userdatabase
    fi
}

ask "Provides the user database: " userdatabase

もちろん、私はアプリケーションが尋ねるすべての質問の変数名として "userdatabase"を使用したくありません。だから私は「動的」変数が必要であることに気づきました。思考をもう少しダイナミックにすると、次のようになります。

ask() {
    read -p "$1" $2

    if [[ -z $$var ]]; then
        echo Empty is not allowed
        ask "$1" $2
    else
        echo $$var
    fi
}

ask "Provides the user database: " $var

ただし、ユーティリティを使用すると、SOMENUMBERvarなどのメッセージが表示されます。明らかに、私はシェルで「動的変数」を正しい方法で使用していないようです。

それでは、質問を受け取る関数とコマンドの変数で埋められる変数名をどのように生成しますかread -p

答え1

最も簡単な場合から始めてください。関数を作成します。

f() { read -p "Type smthng: " $1 ; }

関数呼び出しと変数の割り当て$p入力を保存してから入力を表示します。 後ろに機能終了:

f p ; echo $p

「woof」の入力を求められ、echo $p同じ内容が出力されます。

Type smthng: woof
woof

変数をチェックする1つの方法は、関数を別の関数にラップすることです。

g() { unset $1 ; until f "$1" && eval [ \"\$"$1"\" ] ; do echo wrong ; done ; }

難しい部分は、OPが変数名を関数パラメータとして割り当てようとすることです。「邪悪な」eval分析する。変数を渡す名前関数引数はほとんど行われないし必要はありませんが、これを行う1つの方法を示します。

テストを受けてください:

g p ; echo $p

メッセージが表示されたら、をクリックするとEnterエラーメッセージが表示され、2番目のプロンプトで「foo」と入力します。

Type smthng: 
wrong
Type smthng: foo
foo

OPコードのこの部分は機能しません。

if [[ -z $$var ]]; then

これは現在のPIDを返す変数$$です。bash

 man bash | grep -A 28 "Special Parameters$"  | sed -n '1,3p;28,$p'
   Special Parameters
       The shell treats several parameters specially.  These  parameters  may  only
       be referenced; assignment to them is not allowed.
       $      Expands to the process ID of the shell.  In a () subshell, it expands
              to the process ID of the current shell, not the subshell.

答え2

ask() {
   # $1 ---> message to user
   # $2 ---> "VARIABLE NAME" in which read will store response

   case ${2-} in
      '' | *[!a-zA-Z0-9_]* | [0-9]* )
          echo >&2 "Oops you've selected an invalid variable name: \`$2'"
          exit 1;;
   esac

   read -p "$1" "$2"

   eval "
      case \${$2:++} in
         '' )
               echo >&2 'Empty response not allowed.'
               ask '$1' '$2';;
         * )
            echo \"\${$2}\";;
      esac
   "
}

VarName=${1-'humpty_dumpty'}
ask "Provide the user database: " "$VarName"

答え3

最近見つけた内容を共有したかったです。回答検証に追加の手順を追加しようとしました。また、パスが存在することを確認しましたが、それに対してRakesh Sharmaのソリューションを適用することはできませんでした。最後に私が探していたものを見つけましたが、それは「動的変数」を扱う方法であり、実際の方法は$ {! var}を使用することでした。私の関数の最終バージョンと使い方は次のとおりです。

ask_validate() {

    read -p "$1" $2

    if [ -z ${!2} ]; then
        echo Empty answer is not allowed.
        ask_validate "$1" $2
        return
    fi

    if ! [ -d ${!2} ]; then
        echo You need to provides an existing path
        ask_validate "$1" $2
        return
    fi

    echo The var name is: $2
    echo The var value is: ${!2}
}

ask_validate "Please, provides the host path: " host_path
ask_validate "Please, provides the virtual host configuration path: " virtualhost_path

echo The host path is $host_path
echo The virtual host configuration path is $virtualhost_path

答え4

だから私は空であるかどうかを尋ねて確認する一般的な関数を作成したいと思います。

これは良い考えかもしれません。

その場合、ユーザーが何かを提供するまで関数自体が再帰的に呼び出されます。

これは…いい考えではありません。ループを使用してください。

関数型プログラミング言語では、単純なループの代わりに再帰を使用するのが一般的ですが、シェルの場合はそうではなく、おそらくそれほどスマートではないため、テール呼び出しを最適化する可能性は低くなります。逆に、再帰が深くなると、メモリ使用量が増えます。ここではそれほど多くの反復を実行しないので問題はありませんが、通常はツリーなどのデータ構造を参照するときなど、必要なときにのみ再帰を使用することをお勧めします。

あるいは、変数名を関数に引数として渡すのではなく、基本プログラムで代入を実行できます。

ask() {
        read -p "$1: " a
        while [ -z "$a" ] ; do
                echo "Please give a value" >&2
                read -p "$1: " a
        done
        echo "$a"
}

var=$(ask "please enter some value")    
echo "you gave $var"

もちろん、stdoutが変数に割り当てられているので、警告をstderrにリダイレクトする必要があります。これはreadプロンプトの役割でもあります。たとえば、間接参照をdashサポートしていないようです。${!x}

関連情報