查找| xargs shasum 创建校验和文件本身的校验和(过早)并在检查时失败

查找| xargs shasum 创建校验和文件本身的校验和(过早)并在检查时失败

我的问题(在带有 的脚本中#!/bin/sh)如下:我尝试对目录中的所有文件进行校验和以进行存档。包含所有文件名的校验和(在我的例子中为 sha1)文件应位于同一目录中。假设我们有一个~/test包含文件f1f2: 的目录。

mkdir ~/test
cd ~/test
echo "hello" > f1
echo "world" > f2

现在计算校验和

find -maxdepth 1 -type f -printf '%P\n' | xargs shasum

正是我想要的,它仅列出当前目录的所有文件并计算 sha1 总和(maxdepth 稍后可能会更改)。 STDOUT 上的输出为:

f572d396fae9206628714fb2ce00f72e94f2258f  f1
9591818c07e900db7e1e0bc4b884c945e6a61b24  f2

不幸的是,当尝试将其保存到文件时

find -maxdepth 1 -type f -printf '%P\n' | xargs shasum > sums.sha1

生成的文件显示其自身的校验和:

da39a3ee5e6b4b0d3255bfef95601890afd80709  sums.sha1
f572d396fae9206628714fb2ce00f72e94f2258f  f1
9591818c07e900db7e1e0bc4b884c945e6a61b24  f2  

因此稍后会失败shasum --check,因为保存最后一笔金额时存在额外文件修改的明显问题。

我环顾四周,通过使用-pflag for xargs,我发现它在执行 find 命令之前以某种方式创建了输出文件,因此找到了附加文件并将对其进行校验和...

我知道作为一种解决方法,我可以将校验和保存到另一个位置(通过临时目录mktemp)或在 find 中专门排除它,但我想了解为什么它的行为方式如此 - 在我看来这没有那么有用,例如,如果第一个命令检查输出文件是否已在磁盘上,它永远不会得到正确的答案......

答案1

您可以使用以下方法阻止文件到达xargs

find . -maxdepth 1 -type f ! -name sums.sha1 -printf '%P\n' |
  xargs -r shasum -- > sums.sha1

为了防止文件名中包含空格、换行符、引号或反斜杠的问题,我会使用:

find . -maxdepth 1 -type f ! -name sums.sha1 -printf '%P\0' |
  xargs -r0 shasum -- > sums.sha1

反而。

--是为了避免以-.然而,这对于名为-.如果您使用-print0而不是-printf '%P\0',您就不需要 ,--并且该文件也不会有问题-

答案2

既然您正在使用-maxdepth 1,我假设您不想要递归。如果是这样,只需在 shell 中执行即可:

for f in ~/test/*; do
    shasum -- "$f"
done > sums.sha1

要跳过目录,您可以执行以下操作:

for f in ~/test/*; do
    [ ! -d "$f" ] && shasum -- "$f"
done > sums.sha1

如果您确实需要递归并且正在使用bash,请执行以下操作:

shopt -s globstar
for f in ~/test/**; do
    [ ! -d "$f" ] && shasum -- "$f"
done > sums.sha1

请注意,所有这些方法的优点是可以处理任意文件名,包括带有空格、换行符或其他任何内容的文件名。

答案3

zsh

shasum -- *(D.) > sums.sha1

在进行重定向之前,glob 将被扩展,因此sums.sha1如果它一开始就不存在,则不会被包含在内。

D是包含点文件(隐藏文件)find.是仅选择常规文件(例如您的-type f)。

无论如何要排除它,sums.sha1以防它首先存在:

setopt extendedglob # best in ~/.zshrc
shasum -- ^sums.sha1(D.) > sums.sha1

请注意,那些运行shasum 命令,因此如果列表很大,您最终可能会看到“Arg list too long”错误。要解决这个问题:

autoload zargs
zargs -e/ -- *(D.) / shasum > sums.sha1

我建议使用./*而不是*避免名为-.

答案4

作为 find/xargs 等的替代方案,您可能需要 sha1deep。不过,它可能位于不同的包中 - 在我的盒子上,它位于 md5deep 包中。

正如其他人所说, sums.sha1 是由 shell 在 find 开始之前创建的。一个用! -name sums.sha1to 的技巧find会起作用,就像 will

find -maxdepth 1 -type f -printf '%P\n' | xargs shasum | grep -v ' sums\.sha1$' > sums.sha1

相关内容