我的问题(在带有 的脚本中#!/bin/sh
)如下:我尝试对目录中的所有文件进行校验和以进行存档。包含所有文件名的校验和(在我的例子中为 sha1)文件应位于同一目录中。假设我们有一个~/test
包含文件f1
和f2
: 的目录。
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
,因为保存最后一笔金额时存在额外文件修改的明显问题。
我环顾四周,通过使用-p
flag 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.sha1
to 的技巧find
会起作用,就像 will
find -maxdepth 1 -type f -printf '%P\n' | xargs shasum | grep -v ' sums\.sha1$' > sums.sha1