linux - shell感叹号转义 - touch missing file operand




我怎样才能使用xargs复制文件名称中有空格和引号的文件? (15)

find . -print0 | grep --null 'FooBar' | xargs -0 ...

我不知道grep是否支持 - 无论是xargs支持-0还是Leopard,但在GNU上它都很好。

我试图将一堆文件复制到目录下,并且一些文件的名称中有空格和单引号。 当我尝试用xargs findgrep时,出现以下错误:

find .|grep "FooBar"|xargs -I{} cp "{}" ~/foo/bar
xargs: unterminated quote

任何建议更强大的使用xargs?

这是在MacOS 10.5.3上使用BSD xargs


上面的perl版本对于嵌​​入式换行符不适用(仅适用于空格)。 对于那些你没有GNU工具的solaris,更完整的版本可能是(使用sed)...

find -type f | sed 's/./\\&/g' | xargs grep string_to_find

根据需要调整find和grep参数或其他命令,但sed将修复嵌入的换行符/空格/制表符。


做最原始的海报所需要的最简单的方法是将分隔符从任何空格改为像这样的行尾字符:

find whatever ... | xargs -d "\n" cp -t /var/tmp

在find中使用带有-print0选项的xargs的--null命令行选项。


如果系统上的find和xarg版本不支持-print0-0开关(例如AIX find和xargs),则可以使用以下非常可怕的代码:

 find . -name "*foo*" | sed -e "s/'/\\\'/g" -e 's/"/\\"/g' -e 's/ /\\ /g' | xargs cp /your/dest

这里sed将负责转义xargs的空格和引号。

在AIX 5.3上测试


对于愚蠢的非GNU版本的用户,如果文件名中有撇号,则Bill Starr的解决方案不起作用。 我认为rjb1也有同样的问题,尽管我无法用测试复制它。 Carl Yamamoto-Furst的版本作品。


对我而言,我试图做一些与众不同的事情。 我想将我的txt文件复制到我的tmp文件夹中。 txt文件名包含空格和撇号字符。 这工作在我的Mac。

$ find . -type f -name '*.txt' | sed 's/'"'"'/\'"'"'/g' | sed 's/.*/"&"/'  | xargs -I{} cp -v {} ./tmp/

您可以将所有这些组合到一个find命令中:

find . -iname "*foobar*" -exec cp -- "{}" ~/foo/bar \;

这将处理其中包含空格的文件名和目录。 您可以使用-name来获得区分大小写的结果。

注意: --传递给cp--标志阻止它处理以-开头的文件作为选项。


我发现以下语法适合我。

find /usr/pcapps/ -mount -type f -size +1000000c | perl -lpe ' s{ }{\\ }g ' | xargs ls -l | sort +4nr | head -200

在这个例子中,我正在寻找安装在“/ usr / pcapps”的文件系统中超过1,000,000字节的最大200个文件。

“find”和“xargs”之间的Perl行间隔/空格使每个空格都成为空格,所以“xargs”将任何具有内嵌空白的文件名作为单个参数传递给“ls”。

Bill Starr Fri,2009年1月23日,美国东部时间下午5点40分


我在“xargs”周围创建了一个名为“xargsL”的小型可移植包装脚本,它解决了大部分问题。

与xargs相反,xargsL每行接受一个路径名。 路径名可以包含除了(明显)换行符或NUL字节以外的任何字符。

在文件列表中不允许引用或支持引用 - 您的文件名可能包含各种空白,反斜杠,反引号,外壳通配符等 - xargsL将它们作为文字字符处理,不会造成任何损害。

作为额外的奖励功能,如果没有输入,xargsL将不会运行一次命令!

注意不同之处:

$ true | xargs echo no data
no data

$ true | xargsL echo no data # No output

任何给xargsL的参数都会传递给xargs。

这里是“xargsL”POSIX shell脚本:

#! /bin/sh
# Line-based version of "xargs" (one pathname per line which may contain any
# amount of whitespace except for newlines) with the added bonus feature that
# it will not execute the command if the input file is empty.
#
# Version 2018.76.3
#
# Copyright (c) 2018 Guenther Brunthaler. All rights reserved.
#
# This script is free software.
# Distribution is permitted under the terms of the GPLv3.

set -e
trap 'test $? = 0 || echo "$0 failed!" >& 2' 0

if IFS= read -r first
then
        {
                printf '%s\n' "$first"
                cat
        } | sed 's/./\\&/g' | xargs ${1+"[email protected]"}
fi

将脚本放到$ PATH中的某个目录中,不要忘记

$ chmod +x xargsL

那里的脚本使其可执行。


我稍微玩了一下,开始考虑修改xargs,并意识到对于我们在这里讨论的用例来说,在python中简单的重新实现是一个更好的主意。 一方面,对于整个事物来说,有80行代码意味着很容易找出发生了什么,如果需要不同的行为,你可以用更少的时间将其转化为新的脚本,在某个地方像的答复。

请参阅https://github.com/johnallsup/jda-misc-scripts/blob/master/yargshttps://github.com/johnallsup/jda-misc-scripts/blob/master/zargs.py

用写的yargs(和python3安装),你可以输入

find .|grep "FooBar"|yargs -l 203 cp --after ~/foo/bar

一次复制203个文件。 (这里203当然只是一个占位符,使用203这样的奇怪数字表明这个数字没有其他意义。)

如果你真的想要更快的东西而不需要python,请将zargs和yargs作为原型,并用C ++或C重写。


我遇到了同样的问题。 以下是我解决它的方法:

find . -name '*FoooBar*' | sed 's/.*/"&"/' | xargs cp ~/foo/bar

我用sed用同一行替换每行输入,但用双引号括起来。 在sed手册页中,“ ...替换中出现的和号(`&&')被替换为匹配RE的字符串... ” - 在这种情况下, .* ,整行。

这解决了xargs: unterminated quote错误。


请注意,其他答案中讨论的大多数选项在不使用GNU实用程序(例如Solaris,AIX和HP-UX)的平台上不是标准选项。 有关'标准'xargs行为的信息,请参阅POSIX规范。

我也发现了xargs的行为,即使没有输入,它至少运行一次命令也是令人讨厌的。

我写了自己的xargs(xargl)专用版本来处理名称空间问题(只有新行分开 - 尽管'find ... -print0'和'xargs -0'组合很整洁,因为文件名不能包含ASCII NUL'\ 0'字符。我的xargl并不像完成它需要值得发布那样完整 - 特别是因为GNU的设施至少是一样的。


这是一个便携式(POSIX)解决方案,即不需要findxargscp GNU特定扩展的解决方案:

find . -name "*FooBar*" -exec sh -c 'cp -- "[email protected]" ~/foo/bar' sh {} +

它将正确处理带有嵌入空格,换行符或其他内容的文件和目录,并且比接受的和大部分(如果不是全部)其他答案更有效 (即更快 )。


find | perl -lne 'print quotemeta' | xargs ls -d

我相信这对任何字符都能可靠地工作,除了换行符(并且我怀疑如果你的文件名中有换行符,那么你遇到的问题比这更糟糕)。 它不需要GNU findutils,只需要Perl,所以它应该可以在任何地方工作。







xargs