Bash 脚本的问题

c.s*_*kun 1 bash find

我想编写一个简单的脚本来检测由 Windows 病毒创建的文件。通常它会创建一个 .exe 文件,与它放置的目录同名。

这是脚本。只有在路径名不包含\n 时才有效。有人可以帮我修复这个脚本,拜托!

#!/bin/bash
if [ $# == 0 ]; then
    echo ""
    echo "==== Give me a directory to begin with! ===="
    echo ""
    exit
fi

for f in `find $1 -name '*.exe'` ; do
    filename=`basename "$f" .exe`
    dir_name=`dirname "$f"`
    current_dir_name=`basename "$dir_name"`

    if [ $filename == $current_dir_name ]; then
        rm -f "$f"  # It can't remove files 
                    # where the path contains spaces or \n ??!!
    fi
done
Run Code Online (Sandbox Code Playgroud)

mkm*_*mkm 5

Bash 有一个名为 IFS 的特殊变量。

bash 使用它来了解如何将字符串拆分为文件列表。(内部字段分隔符)

默认情况下,它包含空格、制表符和换行符。

for f in `find ...将拆分包含在 $IFS 变量中的字符。如果 find 命令返回的文件名中有换行符或空格,它将被视为不同的文件名,因此将对名称的每个部分执行循环。

$ ls -l
-rw-r--r-- 1 marko marko 0 2010-11-01 12:06 my?bad.exe
-rw-r--r-- 1 marko marko 0 2010-11-01 12:06 space bad.exe
$ for f in $(find -name "*.exe"); 做回声“迭代($ f)”;完毕
迭代(./空格)
迭代 (bad.exe)
迭代 (./my)
迭代 (bad.exe)

我们可以调整 $IFS 变量,但这很棘手。让我们看看为什么:

(在脚本中测试此代码,以便 IFS 变量的更改不会保留在您的 shell 中,您可能会感到困惑)

$ IFS=""; for f in $(find -name "*.exe"); 做回声“迭代($ f)”;完毕
迭代 (./space bad.exe
。/我的
坏.exe)

如您所见,现在 bash 没有任何规则来拆分 find 命令返回的字符串,并将整个输出视为单个值。

显然,这里的问题是,如果我们使用,for f in `find....我们无法区分文件中包含的换行符和 find 命令生成的换行符。

现在,为了完整起见,我将向您展示如何使您的方法有效,但请在答案末尾查看更简单的解决方案。

我们可以使用其他分隔符来解决您当前的问题:

$ for f in $(find -name "*.exe" -exec echo -n {}: \;); 做回声“迭代($ f)”;完毕;
迭代 (./space bad.exe)
迭代 (./my
坏.exe)
迭代 ()

此处该find -name "*.exe" -exec echo -n {}: \;命令返回以“:”分隔的文件列表(在 Windows 文件名中不合法)。

现在下一步是实际删除这些文件。考虑到最后一个文件以“:”结尾,因此 bash 最后一次使用空字符串进行迭代。

IFS=":"; for f in $(find -name "*.exe" -exec echo -n {}: \;); 如果 [ ! -z "$f" ]; 然后 rm "$f"; fi; 完毕;

您应该也可以像以前一样在此循环中执行 basename/dirname 测试。


然而,这个解决方案是丑陋的,并且仅仅因为我们有一个我们可以依赖的角色。

事实证明,find 命令本身可以为它找到的每个文件执行命令。

find -name "*.exe" -exec ./yourscript.sh {} \;

然后 yourscript.sh 将在 $1 中获取全名,rm "$1"即使它包含换行符和空格,您也可以删除。

find 命令还可用于执行您在脚本中执行的内联 basename/dirname 测试,但它是更高级的主题。