首页 > 解决方案 > Shell dash for 循环跳过前两个参数

问题描述

如何在 shell dash 中使用“$@”跳过前两个参数并在 for 循环中使用其余参数?

例如,我有类似的东西command --option file1 file2 file3。我想跳过前两个参数并遍历所有文件(任意数量的文件)。

我尝试使用以下行:

files=$(echo "$@" | awk '{for (i=2; i<=NF; i++) print $i}' | tr -d '\n')

但是它不提供一行文件,而是提供类似file1file2file3.

我希望能够稍后在 for 循环中单独迭代每个文件名:

for file in "$files"
do
    rm "./desktop/temp/$file"
done

标签: shell

解决方案


我假设“shell dash”是指您使用的是Dash,这是一种符合 Posix 标准的轻量级外壳。与 Bash 相比,Dash 非常有限,不提供数组等功能或复杂的参数替换(如${@:m:n}.

我还假设,通过files=$(echo "$@" | ...)你确定你的论点都不包含空格字符。

也就是说,您的问题是由于| tr -d '\n'删除了用作单词分隔符的行尾的部分。这就是你得到“file1file2file3”的原因。

但是可以增强整个命令。这是一种更好的与 Posix 兼容的方法:

files=$(shift 2; printf '%s ' "$@")

shift在子shell中完成,它不会影响当前shell中的参数列表)

你甚至可以这样做:

(
    shift 2
    for file in "$@"; do
        rm "./desktop/temp/$file"
    done
)

(这里整个循环在一个子shell中执行)

...或编写一个函数:

rm_files()
{
    shift 2
    for file in "$@"; do
        rm "./desktop/temp/$file"
    done
}

rm_file "$@"

最后一个建议:是否真的有必要将参数 1 和 2 保留在参数列表中?您可以执行以下操作:

arg1="$1"
arg2="$2"
shift 2
for file in "$@"; do
    rm "./desktop/temp/$file"
done

...如果你需要一次所有的论点,你可以这样做:

for arg in "$arg1" "$arg2" "$@"; do ...; done

推荐阅读