在while循环bash中通过多个值重复输出循环

时间:2018-09-12 16:14:01

标签: bash

我正在尝试使用bash中的while循环遍历3个文件的内容。它们包含名称,aws帐户和aws帐号的列表。

但是循环是不正确的,它会不断重复列表中的名字和列表中的第一个aws环境。

这是我看到的输出:

AWS user name: aadatiya does not exist in AWS account: company-lab
AWS user name: aadatiya does not exist in AWS account: company-lab
AWS user name: aadatiya does not exist in AWS account: company-lab
AWS user name: aadatiya does not exist in AWS account: company-lab
AWS user name: aadatiya does not exist in AWS account: company-lab
AWS user name: aadatiya does not exist in AWS account: company-lab
AWS user name: aadatiya does not exist in AWS account: company-lab
AWS user name: aadatiya does not exist in AWS account: company-lab

这些是我要读取的文件:

aws_users_all="source_files/aws_users_all.txt"

示例输出:

aadatiya
abigailcharles 
tdunphy
broberts

下一个文件:

aws_env_list="source_files/aws_environments_all.txt"

示例输出:

company-lab
company-stage
company-nonprod
company-prod

最后一个文件:     aws_account_numbers =“ source_files / aws_account_numbers.txt” 样本输出:

  123456789191
  987654321211
  456721231213
  123213512321

这是循环错误的代码:

ofile=source_files/aws_access_keys/company-aws-access-keys-all-accounts.csv
while IFS= read -r aws_user_name
  do 
    while IFS= read -r aws_key
    do
      while IFS= read -r aws_account_num
      do
        user_lives_here=$(aws iam get-user --user-name "$aws_user_name" --profile="$aws_key" 2> /dev/null  | jq -r '.User.UserName')
        if [[ -z "$user_lives_here" ]]; then
          printf "AWS user name: %s does not exist in AWS account: %s\\n(%s)" "$aws_user_name" "$aws_key" "$aws_account_num"
        else
          echo "$aws_user_name,$user_access_key1,$key1_date_created,$key1_last_used,$key1AgeDays,$aws_key,$aws_account_num" >> $ofile
      fi
      done < "$aws_account_numbers"
    done < "$aws_env_list"
  done < "$aws_users_all"

如果我取出一个级别(帐号级别),脚本将按预期运行并产生以下输出:

AWS user name: aadatiya does not exist in AWS account: company-lab
AWS user name: aadatiya does not exist in AWS account: company-bill
AWS user name: aadatiya does not exist in AWS account: company-stage
AWS user name: aadatiya does not exist in AWS account: company-dlab
AWS user name: aadatiya does not exist in AWS account: company-nonprod
AWS user name: aadatiya does not exist in AWS account: company-prod
AWS user name: aadatiya does not exist in AWS account: company-govcloud-admin-nonprod
AWS user name: abigailcharles does not exist in AWS account: company-lab
AWS user name: abigailcharles does not exist in AWS account: company-bill
AWS user name: abigailcharles does not exist in AWS account: company-stage
AWS user name: abigailcharles does not exist in AWS account: company-dlab
AWS user name: abigailcharles does not exist in AWS account: company-nonprod
AWS user name: abigailcharles does not exist in AWS account: company-prod
AWS user name: abigailcharles does not exist in AWS account: company-govcloud-admin-nonprod

我刚刚注释了此级别,它可以工作:

  #while IFS= read -r aws_account_num
  #do
  #done

如何正确执行此操作,以便循环浏览每个名称,aws帐户和AWS帐号,以便每个条目显示一次?

3 个答案:

答案 0 :(得分:4)

您想要使用三个不同的文件描述符的一个循环调用read 三次

while IFS= read -r aws_user_name
      IFS= read -r aws_key <&3
      IFS= read -r aws_account_num <&4; do
    ...
done < "$aws_users_all" 3< "$aws_env_list" 4< "$aws_account_numbers"

答案 1 :(得分:3)

有一种使用paste命令的方式:

while read aws_user_name aws_key aws_account_num ;do
    printf "User: %-16s Key: %-22s AccNum: %s\n" \
        $aws_user_name $aws_key $aws_account_num
    # ...
done < <(
    paste "$aws_users_all" "$aws_env_list" "$aws_account_numbers"
)

示例:

User: aadatiya         Key: company-lab            AccNum: 123456789191
User: abigailcharles   Key: company-stage          AccNum: 987654321211
User: tdunphy          Key: company-nonprod        AccNum: 456721231213
User: broberts         Key: company-prod           AccNum: 123213512321

Nota:这很简单,而每个文件中确实包含一行1字。

...如果您打算在源文件中使用空间,则可以使用另一个定界符

while IFS=@ read -r aws_user_name aws_key aws_account_num ;do
    printf "User: %-16s Key: %-22s AccNum: %s\n" \
        "$aws_user_name" "$aws_key" "$aws_account_num"
    # ....
done < <(
    paste -d@ "$aws_users_all" "$aws_env_list" "$aws_account_numbers"
)

或在 pure

下玩IO

@chepner解决方案附近:

exec 3<$aws_env_list
exec 4<$aws_account_numbers
while read aws_user_name ;do
    read -u 3 aws_key
    read -u 4 aws_account_num
    printf "User: %-16s Key: %-22s AccNum: %s\n" \
        "$aws_user_name" "$aws_key" "$aws_account_num"
    # ...
done <$aws_users_all
exec 3<&-
exec 4<&-

注意:最后两行将关闭 FD 3和4。

答案 2 :(得分:0)

一种方法是在处理之前将所有输入数据加载到数组中

IFS= mapfile -t aws_users <"$aws_users_all"
IFS= mapfile -t aws_envs <"$aws_env_list"
IFS= mapfile -t aws_acct_nums <"$aws_account_numbers"

for aws_user_name in "${aws_users[@]}" ; do
    for idx in ${!aws_envs[*]} ; do
        aws_key=${aws_envs[idx]}
        aws_account_num=${aws_acct_nums[idx]}

        # Code using $aws_user_name, $aws_key, and $aws_account_num
        ...
    done
done

请注意,mapfile是Bash 4.0引入的,因此,如果您使用的是较旧版本的Bash,则此功能将无效。请参阅Read lines from a file into a Bash array,了解适用于较早版本的替代方法(但请注意,可接受的答案非常糟糕)。

将文件加载到内存中似乎是一个坏主意,但实际上这不太可能成为问题。现代机器具有大量内存,而Bash在几乎所有方面都非常慢。如果要加载到内存中的数据太多,则可能有方式要用Bash代码逐行处理的数据太多。