从"查找"到"尾部"的管道



我想得到find输出的最后两行,并将它们复制到某个地方。我试过

find . -iname "*FooBar*" | tail -2 -exec cp "{}" dest ;

但是tail的输出是"无效选项--2"。

此外,我的文件或目录名包含空格。

以下内容应该适用于任何路径。

声明一个函数,使其能够在NUL分离输出上使用headtail

nul_terminated() {
tr 'n' 'n' | "$@" | tr 'n' 'n'
}

然后,您可以使用它在通过tail:后从搜索中获得一个NUL分隔的路径列表

find . -exec printf '%s' {} ; | nul_terminated tail -n 2

然后,您可以通过管道将其发送到xargs并添加您的选项:

find . -iname "*FooBar*" -exec printf '%s' {} ; | nul_terminated tail -n 2 | xargs -I "{}" -0 cp "{}" "dest"

说明:

  1. 当前目录(.)及以下的find文件,名称包含foobar(由于-iname中的i,不区分大小写)
  2. 对于每个文件,运行(-exec)一个命令
  3. 单独打印每个文件路径({}),后跟NUL字符()(;)
  4. 交换换行符和NUL字符(tr 'n' 'n');">
  5. 获取最后两行(即路径;tail -n 2"$@")
  6. 再次交换换行符和NUL字符以获得以NUL分隔的文件名列表(tr 'n' 'n')

xargs命令有点难以解释。它根据需要构建尽可能多的cp ... "dest"命令,以适应操作系统的最大命令长度,将命令中的{}标记替换为实际文件名(-I "{}" ... "{}"),读取参数时使用NUL字符作为分隔符(-0)。

您可以尝试

cp $(find . -iname "*FooBar*" | tail -2 ) dest
find . -iname "*FooBar*"|tail -n2|xargs -i cp "{}" dest

不幸的是,这不适用于包含空格或换行符的文件名。

Robin Green:

$ find . -iname "*FooBar*"|tail -n2|xargs -i cp "{}" dest
不幸的是,这不适用于包含空格或换行符的文件名。

如果文件包含空格,这将起作用(至少对tail)。这是因为查找会将每个文件放在一行,包括空格、制表符和其他特殊字符。

问题是xargs将不会使用空格进行操作。您可以将-0--null选项与xargs一起使用,但这是在设计时考虑到find ... -print0的。

可以使用while循环。

find . -iname "*FooBar*" | tail -n2 | while read file
do
cp "$file" "$dest"
done

由于每行只读取一个项目,$file将包含包含所有不同字符的文件名。只有当$file包含一个NL时,这才不起作用。然后,tail命令本身就会出现问题。幸运的是,在文件名中包含NL的情况非常罕见。

有些人这样做:

while IFS=n read file

它删除了除NL之外的任何东西上的输入分隔符,但这不应该是必要的。

由于您的文件包含2行,因此也有空格,请保留逗号

while read line
do
cp "$line" dest;
done < $(find . -iname "*FooBar*" | tail -2)

我会这么做:

find . -iname "filename" -exec tail -n 2 {} ; > output.txt

最新更新