ShellCheck 警告:“迭代 ls 输出很脆弱。使用 glob。[SC2045]”

Posted

技术标签:

【中文标题】ShellCheck 警告:“迭代 ls 输出很脆弱。使用 glob。[SC2045]”【英文标题】:ShellCheck warning: "Iterating over ls output is fragile. Use globs. [SC2045]" 【发布时间】:2018-05-21 23:58:27 【问题描述】:

我在下面代码的第二行收到一个 ShellCheck 警告 [SC2045]。是否可以忽略它,因为我在尝试最后一个 ls 之前确保目录不为空?

 if [ "$(ls -A "$retryDir")" ]  ; then
    for thisRetryFile in $(ls "$retryDir"/*.tar.gz) ; do
        scp -o ConnectTimeout=30  "$thisRetryFile"  \             
              "$remoteUser@$remoteHost:$remotePath" >> "$BACKUPLOG"
    done
 fi

更新: 看完帖子cmets。我已将行更改为:

for thisRetryFile in "$retryDir"/*.tar.gz ; do

这已删除警告。

【问题讨论】:

见BashPitfall #1。 空目录不是唯一的问题。带空格的文件名也是个问题。 why not parse ls 好的,我明白了。谢谢。 哦,还有包含通配符的文件名。 【参考方案1】:

将循环与 glob 一起使用,并设置 nullglob 以避免在模式不匹配任何内容时执行 scp。 而且您也不需要外部 if 条件, 因为fornullglob 有效地解决了这个问题:

shopt -s nullglob

for thisRetryFile in "$retryDir"/*.tar.gz; do
    scp -o ConnectTimeout=30  "$thisRetryFile" \
          "$remoteUser@$remoteHost:$remotePath" >> "$BACKUPLOG"
done

如果你想捕捉没有文件匹配模式的情况, 你可以这样写,不用shopt -s nullglob:

for thisRetryFile in "$retryDir"/*.tar.gz; do
    if [ -f "$thisRetryFile" ]; then
        scp -o ConnectTimeout=30  "$thisRetryFile" \
            "$remoteUser@$remoteHost:$remotePath" >> "$BACKUPLOG"
        break
    else
        echo "warn: no tar.gz file in dir: $retryDir"
    fi
done

【讨论】:

这真是见仁见智。真正安全的替代方法是处理在您使用通配符的每个位置都没有匹配的情况。然后,您是否使用 nullglob 或其他东西将视情况而定;当你的论点可能消失时,有些事情会变得更难。 @AndyM 是的,就像那样【参考方案2】:

这样更安全。试试看。

 if [ "$(ls -A "$retryDir")" ]  ; then
    for thisRetryFile in $retryDir'/*.tar.gz' ; do
        scp -o ConnectTimeout=30  "$thisRetryFile"  "$remoteUser@$remoteHost:$remotePath" >> "$BACKUPLOG"
    done
 fi

问候!

【讨论】:

不,这仍然违反don't use ls in scripts。

以上是关于ShellCheck 警告:“迭代 ls 输出很脆弱。使用 glob。[SC2045]”的主要内容,如果未能解决你的问题,请参考以下文章

调整语法检查器 shellcheck 的突出显示颜色(带有合成和病原体)

如何删除环境变量的“SC2154”警告[关闭]

所有没有扩展名的文件的shellcheck vscode“shellcheck.ignorePatterns”

如何明确故意分词?

Centos安装shellcheck的方法

在 Jenkins 中记录 shellcheck 结果