首页 > 解决方案 > 具有多个命令的 xargs 仅适用于某些文件

问题描述

我正在尝试(从我的 Macbook 开始)获取与下一行中的规范匹配的所有图像文件的列表,以及它们的大小和 sha512。我这样做是为了审核我分布在多个系统上的数以万计的此类文件。

sudo find /Users \( -iname '*.JPG' -or -iname '*.NEF' -or -iname '*.PNG'
-or -iname '*.RAF' -or -iname '*.PW2' -or -iname '*.DNG' \) -type f -and 
-size +10000k -print0 | xargs -0 -I @@ 
/bin/bash -c '{ stat -n -f"MACBOOK %z " "@@" && shasum -p -a 512 "@@"; }'

运行时,这会正确生成我想要的某些文件的输出,例如我得到的;

MACBOOK 32465640 <SHA512-REDACTED> ?/Users/<REDACTED>/Pictures/Pendleton Roundup/2018/2018-09-13/_DSC3955.NEF

但是对于某些文件,@@ 替换似乎无法正常工作,而是我得到了;

MACBOOK 28130793 shasum: @@:

如果我在 bash 行中添加一个 -v 标志以打印出我希望在出错时执行的命令,我会看到这个;

{ stat -n -f"MACBOOK %z " "/Users/<REDACTED>/Pictures/Photos Library D750.photoslibrary/Masters/2018/07/29/20180729-223141/DSC_3274.NEF"; shasum -p -a 512 "@@"; }

如果我用文件名替换@@ 手动运行该行,它会按预期工作,所以 xargs 的 -I @@ 参数似乎并不总是有效,我不知道原因可能是什么我。

谁能帮我解决这个问题?我尝试将@@ 放在引号中,尝试使用不同的模式并且总是相同的问题。

标签: bashmacosxargs

解决方案


考虑:

find_args=( -false )
for type in jpg nef png raf pw2 dng; do
  find_args+=( -o -name "*.$type" )
done

sudo find /Users '(' "${find_args[@]}" ')' \
  -type f \
  -size +10000k \
  -exec sh -c '
    for arg; do
      stat -n -f"MACBOOK %z " "$arg"
      shasum -p -a 512 "$arg"
    done' _ {} +

使用-exec ... {} +让我们只调用每批文件find的一个副本(与本地平台上的命令行一样多)。sh

更重要的是,不在参数{}内部使用sh -c可以避免命令注入漏洞,该漏洞与原始代码一起允许恶意文件名运行任意命令(当您在 下运行时尤其重要sudo,因此这些命令将以 root 身份执行!)。


推荐阅读