如何使find和printf在bash脚本中工作

时间:2016-08-03 14:35:20

标签: linux bash shell unix

我的环境:Linux Redhat,Bash 3.5

我创建了一个bash脚本,使用下面的脚本列出子目录中的所有文件。

#!/bin/bash
for i in $( find . -maxdepth 1 -mindepth 1 -type d ); do
    b=$(echo $i | awk '{print substr($1,3); }' )
    find $i -type f > $i/$b.txt
done

我想将sha1sum添加到我的脚本中,我将其编辑如下所示。

#!/bin/bash
for i in $( find . -maxdepth 1 -mindepth 1 -type d ); do
    b=$(echo $i | awk '{print substr($1,3); }' )
    find $i -type f ! -iname '*thumbs.db*' -printf "%b:" -exec sha1sum -b {} \; > ./$i/$b.txt
done

第二个代码失败,错误低于

No such file or directory

1 个答案:

答案 0 :(得分:1)

由于您没有指定尝试失败的方式[请参阅下面的注释1],我刚刚提供了一些关于如何解决为每个目录生成校验和列表的基本问题的想法。

使用find既不必要又不安全(如果有任何目录的名称包含空格或shell元字符。

例如,

$( find . -maxdepth 1 -mindepth 1 -type d )

与" glob"

大致相同
./*/

除了glob不对各个目录执行路径名扩展或分词。此外,您可以使用glob */,这将避免显示您不想要的./前缀。

此外,

b=$(echo $i | awk '{print substr($1,3); }' )

可以简单地写成

b=${i:3}   # Bash substring notation

b=${i#./}  # Posix standard prefix deletion

但是,如上所述,您可以使用glob,从而避免任何必须删除前缀。

所以你可以简单地写一下:

#!/bin/bash
for b in */; do
    find "$b" -type f > "$b/$b.txt"
done

注意变量扩展的引号。如果你真的需要%b格式来打印文件名,那么你肯定需要引用扩展来避免空格和shell元字符的问题,但无论如何你应该养成引用变量扩展的习惯。

这将产生与您的脚本略有不同的输出,因为它不会将./放在输出文件中每行的开头,但如果您真的想要它可以使用{{1 }}

我不明白为什么你觉得需要使用find "./$b" ...输出SHA-1校验和的文件名,因为printf已经打印了文件名。它确实是在校验和之后而不是之前这样做的。这种行为实际上是有充分理由的:因为无法知道文件名可能包含哪些字符,所以首先放置校验和可以更容易地解析输出。

请注意,在sha1sum的输出中,每个名称包含反斜杠或换行符的文件的输出,校验和行将以反斜杠开头,文件名中的反斜杠和换行符将被转义。这产生的效果有点类似于使用sha1sum格式的printf。

如果你真的想要改变订单,你可以用awk轻松完成:

%b

使用#!/bin/bash for b in */; do find "$b" -type f '!' -iname '*thumbs.db*' -exec sha1sum {} + | awk '{print "$2:$1"}' > "$b/$b.txt" done 代替+来终止;选项,让-exec执行带有文件名列表的命令,而不仅仅是单个文件名,这是更多高效。

注释

  1. 请参阅我引用的Stack Overflow help page

      

    寻求调试帮助的问题("为什么这段代码不起作用?")必须包括所需的行为,特定的问题或错误以及在问题本身中重现它所需的最短代码。没有明确问题陈述的问题对其他读者没用。

    "它没有工作"是 a"特定问题或错误"。您应该始终包含错误消息的文字文本或明确说明程序结果如何不符合您的期望。