使用“find -exec {} +”时遇到一些问题

使用“find -exec {} +”时遇到一些问题

免责声明:我是 Unix/Linux 的新手,但我期待学习!我已经尝试在这个 stackexchange 上搜索并阅读 the man find,但我似乎无法弄清楚这一点。

我想使用该find ... -exec {} +命令递归地查找具有特定文件扩展名的所有文件,并在文件列表上运行命令。我需要转换大约 100k 个文件。我正在运行的命令接受文件名(或文件名列表,例如f1 f2 f3)作为参数,但我还需要指定其他参数来运行该命令。

到目前为止我尝试过的:

这有效:

find . -iname "*.extension" -exec <command> {} <additional parameters> \;

这似乎不起作用:

find . -iname "*.extension" -exec <command> {} <additional parameters> +

我收到错误消息,find: missing argument to '-exec'。我猜我无法在{}?之后指定其他参数

一些注意事项:

该命令将文件名作为第一个参数,然后我需要指定一些附加参数,例如输出目录-o <outputDir>和从文件中提取的变量-v <var1,var2,...>

我正在 Ubuntu 12.04 的终端上运行它,如果这有什么区别的话。

答案1

find . -iname "*.extension" -exec sh -c '
  exec <command> "$@" <additional parameters>' sh {} +

使用“find ... -exec sh -c '...' sh {} +”的 find 命令如何工作?了解详情。

答案2

有了 ,+它将列出由空格分隔的多个文件名{}(这将是一个很长的列表,因为您有 100000 个文件),而不仅仅是一个文件名。既然如此,则{}需要在命令末尾出现。

请参阅find(1)下面的手册页-exec command {} +

答案3

假设所有目录和文件都有常规名称,即不包含空格、换行符或类似名称,即使文件数量巨大,这也应该有效:

find . -iname "*.extension" -exec sh -c '
command="<command>"
additionalParameters="<additional parameters>"
h=$(($#/2))
cmd="$command "
for i in $(seq 1 $h);do
        cmd="$cmd $(eval echo \$$i) "
done
cmd="$cmd $additionalParameters"
$cmd
shift $h
$command "$@" $additionalParameters' sh {} +

理由:

使用+标点符号时,find 会构建尽可能大的命令。涉及两个限制:允许的最大参数数量(在 Gnu/Linux 上应为 128k)和参数列表的最大大小(在 Gnu/Linux 上应为 2 MB)。问题是调用的命令需要额外的参数(附加参数)。添加它们会溢出限制,导致“参数过多错误”。我建议的脚本将构建的参数列表分成两部分,并运行两个命令,而不是每个块运行一个命令,因此添加额外的参数不会出现问题。

答案4

您可以使用这个脚本:

#! /bin/bash

cmd=echo

test $# -gt 2 || exit 2
num_trailing_args="$1"
[[ $num_trailing_args =~ ^(0|[1-9][0-9]*)$ ]] ||
  { echo "Illegal first argument ('${num_trailing_args}'); aborting"; exit 2; }
test $# -lt $((num_trailing_args+2)) &&
  { echo "Too few arguments; aborting"; exit 2; }
shift
trailing_args=()
for((i=0;i<num_trailing_args;i++)); do
        trailing_args[i]="$1"
        shift
done

"$cmd" "$@" "${trailing_args[@]}"

然后使用

find ... -exec args_change_script.sh 3 t1 t2 t3 {} +

命令的名称不应长于脚本的名称(只是为了确定)。

相关内容