2つのコマンドの出力から連想配列を作成する

インポートされたpasswdファイルに基づいてユーザーディレクトリを作成しようとしていますが、データをにロードしようとしています。連想配列:array [username] = directory。フィールドを個別の配列にロードすることはできますが、各フィールドがすべてのディレクトリに関連付けられるため、関連付けを正しく行うことができません。

USERLIST=$(cat /usrmkr/in.out | awk -F ":" "{print $1}") DIRLIST=$(cat /usrmkr/in.out | awk -F ":" "{print $6}") declare -A USERARRAY func_StoreData() { USERARRAY[$1]="$2" return $? } for ((u=0;u<${USERLIST[@]};u++)); do func_StoreData ${USERLIST[$u]} ${DIRLIST[$u]} done for i in ${!USERARRAY[@]}; do echo "making directory for $i in ${USERARRAY[$i]}" #Do stuff done 

コメント

  • 既存の回答のいずれかで問題が解決した場合は、次の方法で受け入れることを検討してください。チェックマーク。ありがとうございます!

回答

コロンで分割するように読み取りを指示して、bashですべてを直接読み取ることができます。 :

declare -A userarray while IFS=: read -r username password uid gid gecos home shell; do userarray[$username]=$home done < /usrmkr/in.out 

回答

 eval declare -A USERARRAY=( $(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out) )  

awkスクリプトは、[key]=val形式で出力を生成しますbash連想配列の複数の要素を設定する場合に必要であり、キーまたは値のいずれかにスペースやタブなどがある場合は、キーと値の両方を二重引用符で囲みます(["key"]="value")。 。

\nを区切り文字として使用して、awk他のツールで出力します(ただし、awkは、他のツールで実行したいほとんどのことを実行できます)。

コマンド置換 だけで十分です。 。ただし、IMOが原因で、( ... )配列定義内の最初の非空白文字がない場合、bashのバグが発生します。 ” ta [、エラーメッセージmust use subscript when assigning associative arrayを生成するだけです。

eg USERARRAYを設定する次の両方の試みは失敗します:

 $ bash --version | head -1 GNU bash, version 4.3.46(1)-release (x86_64-pc-linux-gnu) $ declare -A USERARRAY=($(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out)) bash: USERARRAY: $(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out): must use subscript when assigning associative array $ UA=$(awk -F: "{ printf "[\"%s\"]=\"%s\"\n", $1, $6}" /usrmkr/in.out) $ declare -A USERARRAY=( $UA ) bash: USERARRAY: $UA: must use subscript when assigning associative array  

解決策は回答の上部にあるコード例のように、ハッシュ配列を宣言するときにevalを使用します。または、

eval declare -A USERARRY=( $UA ) 

コメント

  • 1。これはevalを使用します-もちろん、'にはコマンドインジェクションのリスクがあります。 'この場合、問題はないと思います'ただし、私の答えはOP

固有の&おそらく精査済み/正常な入力ファイル。 2. " 拡張を引用するのを忘れた "-え?何? '引用符の問題は見当たりません。awkコードは配列のキーと値の両方を明示的に引用します。 3.ところで、ほぼ2年後、bash v4.4.19(1)-リリースまだでは、cmd-substまたはさらには直接使用できません'ハッシュ宣言の変数:declare -A array=( $(...) )は同じエラーで失敗するため、evalが引き続き必要です

  • @St é phaneChazelas '引用の問題がある場合は、その方法と理由を説明してください。できれば、この質問と回答に関連する有効な/ etc / passwdスタイルの入力を使用した実際の例を使用してください。一般的で明白な"だけでなく、ガベージデータをフィードすると、'予測できない潜在的に危険な結果が得られます"。
  • '通常、通常の/etc/passwdデータ。つまり、言い換えると、⚠通常の/etc/passwdデータでは問題ないはずですが、コマンドインジェクションの脆弱性を構成するため、このアプローチを任意のデータに使用しないでください。具体的には、データに'、`"、バックスラッシュ、 $*?[、スペースタブまたはNUL文字。
  • 引用の問題については、たとえば bash / POSIXシェルで変数を引用するのを忘れた場合のセキュリティへの影響を参照してくださいとそこにリンクされている質問は、展開を引用符で囲まないままにすることの意味を確認します。
  • 古いバージョンのbashには、' a =(" $ x ") `は、1つの要素が$x $x[123]=qweのようなものだったとき(bashが連想配列をサポートする前でした)。'の真のbashは、連想配列をa=("$x")$xは、a=([$k]=$v)構文に加えて、[...]=)で始まる必要がありますが、その場合、指定する方法を定義する必要があります。 ]文字を含むキー。いずれにせよ、私はそれをバグとは呼びませんが、設計上の決定(ここではbashが構文をコピーしたkshによって行われました)。
  • 回答

    2つのリストをマージするのではなく、リストを返すことで、単一のループで配列を作成できます(そして、適切な方法としてawkを1回呼び出す)。 user:dirエントリの数を、変数展開で分割します:

    #!/bin/bash declare -A USERARRAY for u in $(awk -F: "{print $1 ":" $6}" /usrmkr/in.out) do user=${u%:*} dir=${u#*:} USERARRAY[$user]=$dir done 

    回答

    zshは、より便利で、より一般的です(tclまたはperlに類似)連想配列全体を宣言する方法:array=(key1 value1 key2 value2...)

    typeset -A userarray IFS=$":\n\n" userarray=($(cut -d : -f 1,6 < /usrmkr/in.out)) 

    ダブリング\nは、ksh93のように、改行の特別なステータスを IFS-空白文字として削除します。これがないと、foo:\nbar:xは、「foo」、「」、「bar」、「x」ではなく、「foo」、「bar」、「x」に分割されます。

    、構文はksh93と同じ厄介なものです:array=([key1]=value1 [key2]=value2)なので、簡単に出力を取得することはできません他の人が示しているように、一度に1つの要素の割り当てを行うループを使用する以外の方法でコマンドを連想配列に変換します。

    bash連想配列( ksh93またはzsh)とは対照的に、キーを空の文字列にすることはできないという制限があります(ここでは問題ありません)。今回ksh93と共有される別の制限は、キーも値もNULバイトを含めることができないことです(ここでも問題ではありません)。

    (連想配列のサポートはksh93で最初(1993)から、1998年にzsh(3.1.5-pws-3)に追加され、2009年にbashに追加されました( 4.0))

    コメント

    • なぜ' \ n IFSに2回入りますか?
    • @rubystallion編集を参照

    コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です