bash 进行for循环

这是 Shell 中很常见的需求,不要定义 PATH1PATH2PATH3 再一个个处理 ,而是把所有路径放到一个列表中,再用 for 循环。

方法一:使用数组(推荐,bash)

bash 复制代码
#!/bin/bash

dirs=(
    "/tmp/log"
    "/home/user/data"
    "/opt/test"
)

for dir in "${dirs[@]}"; do
    echo "Processing $dir"

    if [ -d "$dir" ]; then
        ls "$dir"
    else
        echo "$dir does not exist"
    fi
done

优点:

  • 路径中可以包含空格
  • 易于维护
  • 添加路径只需增加一行

方法二:直接在 for 中写路径

如果路径数量不多:

bash 复制代码
for dir in \
    "/tmp/log" \
    "/home/user/data" \
    "/opt/test"
do
    echo "$dir"
done

方法三:变量保存多个路径

bash 复制代码
DIRS="/tmp/log /home/user/data /opt/test"

for dir in $DIRS
do
    echo "$dir"
done

注意:

这种方法不能处理包含空格的路径,例如:

复制代码
/home/user/my dir

会被拆成两个字符串。


方法四:从文件读取

例如 dirs.txt

text 复制代码
/tmp/log
/home/user/data
/opt/test

脚本:

bash 复制代码
while IFS= read -r dir
do
    echo "$dir"
done < dirs.txt

适合路径很多的时候。


如果你的环境是 tcsh

由于你之前提到经常使用 tcsh,写法有所不同:

tcsh 复制代码
set dirs = ( \
    /tmp/log \
    /home/user/data \
    /opt/test \
)

foreach dir ($dirs)
    echo $dir

    if ( -d $dir ) then
        ls $dir
    else
        echo "$dir does not exist"
    endif
end

推荐

  • bash :使用数组(方法一)。
  • tcsh :使用 set dirs = (...) + foreach

这两种方式都是最清晰、最容易维护的写法。

如果每个目录都有一个对应的文件名,最好的做法是把它们成对保存,而不是分别保存两个列表,否则容易对应错。

方法一:两个数组(bash,推荐)

bash 复制代码
#!/bin/bash

dirs=(
    "/tmp/log1"
    "/tmp/log2"
    "/tmp/log3"
)

files=(
    "run.log"
    "error.log"
    "debug.log"
)

for ((i=0; i<${#dirs[@]}; i++)); do
    dir="${dirs[i]}"
    file="${files[i]}"

    echo "Processing: $dir/$file"

    if [ -f "$dir/$file" ]; then
        cat "$dir/$file"
    else
        echo "$dir/$file does not exist"
    fi
done

输出类似:

复制代码
Processing: /tmp/log1/run.log
Processing: /tmp/log2/error.log
Processing: /tmp/log3/debug.log

方法二:把目录和文件名写在一起(更推荐)

如果它们是一一对应的,可以直接保存完整路径:

bash 复制代码
paths=(
    "/tmp/log1/run.log"
    "/tmp/log2/error.log"
    "/tmp/log3/debug.log"
)

for path in "${paths[@]}"; do
    echo "$path"

    if [ -f "$path" ]; then
        cat "$path"
    fi
done

这是最简单、最不容易出错的方式。


方法三:关联关系(键值对)

如果一个目录始终对应一个文件,可以用关联数组(需要 Bash 4+):

bash 复制代码
declare -A logs

logs["/tmp/log1"]="run.log"
logs["/tmp/log2"]="error.log"
logs["/tmp/log3"]="debug.log"

for dir in "${!logs[@]}"; do
    file="${logs[$dir]}"
    echo "$dir/$file"
done

如果你使用的是 tcsh

tcsh 没有数组索引和关联数组那么方便,通常用两个列表:

tcsh 复制代码
set dirs  = ( /tmp/log1 /tmp/log2 /tmp/log3 )
set files = ( run.log error.log debug.log )

@ i = 1
while ( $i <= $#dirs )
    echo "$dirs[$i]/$files[$i]"
    @ i++
end

推荐选择

根据你之前的问题,你主要写的是 bash 脚本,因此建议:

  • 如果目录和文件名固定对应:直接保存完整路径(方法二),最简洁。
  • 如果目录和文件名后续可能分别使用:使用两个数组,通过相同索引对应(方法一),可维护性最好。