How can I use xargs to copy files that have spaces and quotes in their names?

后端 未结 22 1059
春和景丽
春和景丽 2020-12-02 03:49

I\'m trying to copy a bunch of files below a directory and a number of the files have spaces and single-quotes in their names. When I try to string together find

相关标签:
22条回答
  • 2020-12-02 04:20

    Just don't use xargs. It is a neat program but it doesn't go well with find when faced with non trivial cases.

    Here is a portable (POSIX) solution, i.e. one that doesn't require find, xargs or cp GNU specific extensions:

    find . -name "*FooBar*" -exec sh -c 'cp -- "$@" ~/foo/bar' sh {} +
    

    Note the ending + instead of the more usual ;.

    This solution:

    • correctly handles files and directories with embedded spaces, newlines or whatever exotic characters.

    • works on any Unix and Linux system, even those not providing the GNU toolkit.

    • doesn't use xargs which is a nice and useful program, but requires too much tweaking and non standard features to properly handle find output.

    • is also more efficient (read faster) than the accepted and most if not all of the other answers.

    Note also that despite what is stated in some other replies or comments quoting {} is useless (unless you are using the exotic fishshell).

    0 讨论(0)
  • 2020-12-02 04:21

    You can combine all of that into a single find command:

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

    This will handle filenames and directories with spaces in them. You can use -name to get case-sensitive results.

    Note: The -- flag passed to cp prevents it from processing files starting with - as options.

    0 讨论(0)
  • 2020-12-02 04:21

    Be aware that most of the options discussed in other answers are not standard on platforms that do not use the GNU utilities (Solaris, AIX, HP-UX, for instance). See the POSIX specification for 'standard' xargs behaviour.

    I also find the behaviour of xargs whereby it runs the command at least once, even with no input, to be a nuisance.

    I wrote my own private version of xargs (xargl) to deal with the problems of spaces in names (only newlines separate - though the 'find ... -print0' and 'xargs -0' combination is pretty neat given that file names cannot contain ASCII NUL '\0' characters. My xargl isn't as complete as it would need to be to be worth publishing - especially since GNU has facilities that are at least as good.

    0 讨论(0)
  • 2020-12-02 04:21

    If find and xarg versions on your system doesn't support -print0 and -0 switches (for example AIX find and xargs) you can use this terribly looking code:

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

    Here sed will take care of escaping the spaces and quotes for xargs.

    Tested on AIX 5.3

    0 讨论(0)
  • 2020-12-02 04:21

    I played with this a little, started contemplating modifying xargs, and realised that for the kind of use case we're talking about here, a simple reimplementation in Python is a better idea.

    For one thing, having ~80 lines of code for the whole thing means it is easy to figure out what is going on, and if different behaviour is required, you can just hack it into a new script in less time than it takes to get a reply on somewhere like Stack Overflow.

    See https://github.com/johnallsup/jda-misc-scripts/blob/master/yargs and https://github.com/johnallsup/jda-misc-scripts/blob/master/zargs.py.

    With yargs as written (and Python 3 installed) you can type:

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

    to do the copying 203 files at a time. (Here 203 is just a placeholder, of course, and using a strange number like 203 makes it clear that this number has no other significance.)

    If you really want something faster and without the need for Python, take zargs and yargs as prototypes and rewrite in C++ or C.

    0 讨论(0)
  • 2020-12-02 04:26

    I ran into the same problem. Here's how I solved it:

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

    I used sed to substitute each line of input with the same line, but surrounded by double quotes. From the sed man page, "...An ampersand (``&'') appearing in the replacement is replaced by the string matching the RE..." -- in this case, .*, the entire line.

    This solves the xargs: unterminated quote error.

    0 讨论(0)
提交回复
热议问题