追加到数组并保留变量在循环之外

时间:2015-05-11 08:59:35

标签: bash

请注意,这是一个伪代码来说明问题。我刚才使用了ls,我知道I shouldn't parse the output of ls。原始脚本用于迭代AWS S3存储桶。

目录结构:

# tree
.
├── dir1
│   ├── d1_file1
│   ├── d1_file2
│
└── dir2
    ├── d2_file1
    ├── d2_file2

2 directories, 4 files

期望的结果:

# bash tmp.sh
dir1 has 2 files(s)
dir1 files: d1_file1 d1_file2
dir2 has 2 files(s)
dir2 files: d2_file1 d2_file2
Warnings: 2

命令分组 - 文件已正确列出,但WARNING变量因管道创建的子shell而丢失。

#!/bin/bash

WARNING=0

list=(
dir1
dir2
)

for dir in ${list[@]}; do
    ls -1 ./tmp/${dir} |
    {
    while read -a file; do
       files+=(${file})
    done
    echo "${dir} has ${#files[@]} files(s)"
    echo "${dir} files: ${files[@]}"
    if [ ${#files[@]} -gt 1 ]; then
        (( WARNING++ ))
    fi
}
done
echo "Warnings: ${WARNING}"

----- Output -----

dir1 has 2 files(s)
dir1 files: d1_file1 d1_file2
dir2 has 2 files(s)
dir2 files: d2_file1 d2_file2
Warnings: 0

流程替换 - WARNING变量在循环外保留,但输出不正确。

#!/bin/bash

WARNING=0

list=(
dir1
dir2
)

for dir in ${list[@]}; do
    while read -a file; do
       files+=(${file})
    done  < <(ls -1 ./tmp/${dir})
    echo "${dir} has ${#files[@]} files(s)"
    echo "${dir} files: ${files[@]}"
    if [ ${#files[@]} -gt 1 ]; then
        (( WARNING++ ))
    fi
done
echo "Warnings: ${WARNING}"

----- Output -----

dir1 has 2 files(s)
dir1 files: d1_file1 d1_file2
dir2 has 4 files(s)
dir2 files: d1_file1 d1_file2 d2_file1 d2_file2
Warnings: 2

此处文档 - 此处警告的输出和数量不正确

#!/bin/bash

WARNING=0

list=(
dir1
dir2
)

for dir in ${list[@]}; do
    while read -a file; do
       files+=(${file})
    done  <<<$(ls -1 ./tmp/${dir})
    echo "${dir} has ${#files[@]} files(s)"
    echo "${dir} files: ${files[@]}"
    if [ ${#files[@]} -gt 1 ]; then
        (( WARNING++ ))
    fi
done
echo "Warnings: ${WARNING}"

----- Output -----

dir1 has 1 files(s)
dir1 files: d1_file1
dir2 has 2 files(s)
dir2 files: d1_file1 d2_file1
Warnings: 1

请问您应该采用什么方法来获得理想的结果,以及在我的案例中实际推荐的方法。

1 个答案:

答案 0 :(得分:1)

不按你想要的方式工作的理由

Command grouping

正如你所说,由于子shell而导致警告丢失,但是文件数组也是如此,使得该部分的外观正常工作

Process Substitution

与子shell不同,files数组不会被重置,因此每个后续的循环/目录仍然包含前一个的文件。

Here Document

错误地添加到数组中,由于从here文档输出ls的方式,一次只添加一个文件。

解决方案

您可以使用进程替换,只需在循环之间重置数组,如

#!/bin/bash

WARNING=0

list=(
dir1
dir2
)

for dir in ${list[@]}; do
    {
    while read -a file; do
       files+=(${file})
    done < <(ls -1 tmp/${dir})
    echo "${dir} has ${#files[@]} files(s)"
    echo "${dir} files: ${files[@]}"
    if [ ${#files[@]} -gt 1 ]; then
        (( WARNING++ ))
    fi
        unset files   ## THIS LINE
}
done
echo "Warnings: ${WARNING}"

这假设您实际上并不想要文件数组,只想输出它们

P.s Don解析ls;)