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

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

答え1

bashを使用して内容全体を直接読み取ることができ、読み取りにコロンで区切るように指示できます。

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

答え2

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

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

他のツールを使用して出力を\nより簡単に後処理するには、区切り文字を使用します(とにかく、他のツールを使用して実行したいほとんどの作業を実行できますが)。awkawk

コマンドの置き換えしなければならないそれ自体は十分ですが、配列定義IMOのバグが原因で、配列定義の空白以外のbash最初の文字がaで( ... )ない場合[にのみエラーメッセージが生成されますmust use subscript when assigning associative array

たとえば、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 )

答え3

awk両方のリストをマージするのではなく、user:dirエントリのリストを返し、変数拡張を使用して分割して単一のループ(および良い測定のための1回の呼び出し)で配列を構築できます。

#!/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

答え4

zsh連想配列全体を宣言するより便利で一般的な(tclまたは同様の)方法があります。perlarray=(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」に分割されます。

使用すると、構文はbash: と同じなので、他の人が示すように、一度に1つの要素を割り当てるためにループを使用せずに、コマンドの出力を連想配列に簡単に配置することはできません。ksh93array=([key1]=value1 [key2]=value2)

bash連想配列(およびksh93/相対配列)には、zshキーを空の文字列にすることはできないという制限があります(ここでは問題ではありません)。この共有のもう1つの制限ksh93は、キーと値の両方にNULバイトを含めることができないことです(ここでも問題ではありません)。

(ksh93は最初(1993)から連想配列をサポートし、zsh1998(3.1.5-pws-3)とbash2009(4.0)にサポートが追加されました)

関連情報