0

我有一个正在尝试优化的脚本xargs。当前版本使用findwith-exec调用命令:

find -type f -iname "*.mp4" -print0 -printf '\n' -exec getfattr -d --absolute-names {} \;

之后,我可以使用以下方式进行管道传输grep

grep -z -P user\.md5\=\"$input_search_hash\"

过滤结果,同时保持整个输出-z

我需要从每个文件“保留”返回的整个输出getfattr,因为我需要具有匹配扩展属性的文件名,然后将其传递sed给以提取它。如果我需要在扩展属性中grep搜索具有多个匹配项的文件,也存在顺序有多个命令的情况。问题是输出:

find -type f -iname "*.mp4" -print0 | xargs -0 getfattr -d --absolute-names

未以grep会以这种方式过滤的方式格式化。这确实适用于该-exec方法。我可以将附加选项传递给xargs或传递一些附加命令,这些命令将格式化输出以使 grep 正确复制 grep 的行为-exec?我猜在喂食之前我需要某种换行符才能grep喜欢-printf '\n'-exec方法中的功能。我只是getfattr用来“搜索”扩展属性,而不是grep根本不需要输出,但它无法通过提供 xattr 名称和值来做到这一点。

例子

输入来自find命令,它是任意目录结构中的视频文件列表。getfattr对于每个文件,每个命令的输出如下:

# file: /path/to/file/test.mp4
user.md5="0e29a7f555af518872771689e28d998d"
user.quality="10"
user.sha256="d49ba58e3b30f4ef8c81d19ce960edcf6552977bb8adb79b5b9a677ba9a54b2b"
user.size="1645645"

如果我尝试使用该方法grep的输出,例如质量值为“10”,我将得到如下结果:find+

# file: /path/to/file/test.mp4
user.md5="8cf97b888e6fdbed27b02233cd6779f5"
user.quality="12"
user.sha256="613d16b2a0270e2e5f81cfd58b1eacf710a65b82ce2dab49a1e415275440f429"
user.size="1645645"

# file: /path/to/file/test1.mp4
user.md5="3c5a39f1ceefce1e124bcd6786a99155"
user.quality="10"
user.sha256="0d7128a7642d24ea879bbfb3de812b7939b618d8af639f07d5104c954c8049c3"
user.size="5674567"

# file: /path/to/file/test2.mp4
user.md5="0e29a7f555af518872771689e28d998d"
user.quality="6"
user.sha256="d49ba58e3b30f4ef8c81d19ce960edcf6552977bb8adb79b5b9a677ba9a54b2b"
user.size="15645"

所有找到的文件find都被返回,并且要从中搜索的字符串grep,在这个例子user.quality="10"中,被突出显示,但其他文件 test.mp4 和 test2.mp4 仍然有输出打印 post-grep。换句话说,find可能会找到 1000 个 mp4 文件,其中可能有 20 个有user.quality="10"条目,但即使申请grep搜索该字符串仍会返回 1000 个文件名(在 之后sed)。

使用时不会发生这种情况\;。我唯一能摆脱的grep就是:

# file: /path/to/file/test.mp4
user.md5="3c5a39f1ceefce1e124bcd6786a99155"
user.quality="10"
user.sha256="0d7128a7642d24ea879bbfb3de812b7939b618d8af639f07d5104c954c8049c3"
user.size="5674567"

这是预期的行为。

4

1 回答 1

0

xargs对比find -exec

对我来说,您似乎想使用xargs而不是find -exec {} \;加快速度。

是的,xargs比 快find -exec {} \;,不是因为它做同样的工作效率更高,而是因为它做的工作不同!

  • find -exec {} \;为每个文件调用一次(getfattr file1、 thengetfattr file2等)。
  • xargs将尽可能多的文件塞进一个调用中 ( getfattr file1 file2 file3 ...)。无需为此使用
    即可实现相同的行为(甚至更快)。find -exec {} +xargs

随着xargsfind -exec {} +你放松对输出格式的控制。只有一个调用,getfattr所以程序决定在 之间打印什么file1file2依此类推。getfattr无法自定义其输出格式。

没问题!你可以 ...

解析getfattr的输出

......很容易。
对于初学者,我们假设所有路径名都很正常。空格、*?都可以。对于包含反斜杠和换行符的非常不寻常的路径名,请参见最后一节。

如果您使用-n user.md5而不是仅输出相关属性-d,那么您知道每个文件的输出(如果有)始终采用以下形式

# file: path in a single line
user.md5=encoded value of the attribute

没有属性的文件user.md5根本不打印。它们会引起一个警告stderr,可以通过2> /dev/null.

现在,grep 匹配属性。也用于grep -B1打印每个匹配项(即路径)上方的行。然后使用sed -ngrep -o提取文件名。

find -type f -iname '*.mp4' -exec getfattr -n user.md5 --absolute-names {} + 2> /dev/null |
grep -B1 -Fx "user.md5=\"$input_search_hash\"" |
sed -n 's/^# file: //p'

上面的命令打印所有具有user.md5value属性的 mp4 文件的路径$input_search_hash

处理不寻常的文件名

至少我在 Debian 10 上的版本(getfattr 2.4.48由 Andreas Gruenbacher 编写)总是在一行中打印文件名。换行符使用编码\012,反斜杠使用编码\134。因此,可以安全地处理这些文件。

上面的命令有效,但只打印编码的文件名。要获得实际的文件名,您必须扩展sed命令或添加另一个命令来解释八进制转义序列。对我来说,getfattr只有转义\n,\r\\, 因此sed 's:\\012:\n:g;s:\\015:\r:g;s:\\134:\\:g'应该足以打印。为了进一步处理,您可能想要使用tr \\n \\0 | sed -z ...,这样文件名由空字节分隔。

要测试为您转义了哪些字符,请创建一个包含所有允许字节的文件名并getfattr打印其名称:

f=$(printf $(printf '\\%o' $(seq 1 255)) | tr -d /)
touch "$f"
setfattr -n user.md5 -v 123 "$f"
getfattr -n user.md5  "$f"
rm "$f"
于 2020-06-12T11:05:21.450 回答