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

后端 未结 22 1056
春和景丽
春和景丽 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:14

    With Bash (not POSIX) you can use process substitution to get the current line inside a variable. This enables you to use quotes to escape special characters:

    while read line ; do cp "$line" ~/bar ; done < <(find . | grep foo)
    
    0 讨论(0)
  • 2020-12-02 04:15

    Frame challenge — you're asking how to use xargs. The answer is: you don't use xargs, because you don't need it.

    The comment by user80168 describes a way to do this directly with cp, without calling cp for every file:

    find . -name '*FooBar*' -exec cp -t /tmp -- {} +
    

    This works because:

    • the cp -t flag allows to give the target directory near the beginning of cp, rather than near the end. From man cp:
       -t, --target-directory=DIRECTORY
             copy all SOURCE arguments into DIRECTORY
    
    • The -- flag tells cp to interpret everything after as a filename, not a flag, so files starting with - or -- do not confuse cp; you still need this because the -/-- characters are interpreted by cp, whereas any other special characters are interpreted by the shell.

    • The find -exec command {} + variant essentially does the same as xargs. From man find:

       -exec command {} +                                                     
             This  variant  of the -exec action runs the specified command on
             the selected files, but the command line is built  by  appending
             each  selected file name at the end; the total number of invoca‐
             matched  files.   The command line is built in much the same way
             that xargs builds its command lines.  Only one instance of  `{}'
             is  allowed  within the command, and (when find is being invoked
             from a shell) it should be quoted (for example, '{}') to protect
             it  from  interpretation  by shells.  The command is executed in
             the starting directory.  If any invocation  returns  a  non-zero
             value  as exit status, then find returns a non-zero exit status.
             If find encounters an error, this can sometimes cause an immedi‐
             ate  exit, so some pending commands may not be run at all.  This
             variant of -exec always returns true.
    

    By using this in find directly, this avoids the need of a pipe or a shell invocation, such that you don't need to worry about any nasty characters in filenames.

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

    For those who relies on commands, other than find, eg ls:

    find . | grep "FooBar" | tr \\n \\0 | xargs -0 -I{} cp "{}" ~/foo/bar
    
    0 讨论(0)
  • 2020-12-02 04:17

    This is more efficient as it does not run "cp" multiple times:

    find -name '*FooBar*' -print0 | xargs -0 cp -t ~/foo/bar
    
    0 讨论(0)
  • 2020-12-02 04:18

    You might need to grep Foobar directory like:

    find . -name "file.ext"| grep "FooBar" | xargs -i cp -p "{}" .
    
    0 讨论(0)
  • 2020-12-02 04:19

    bill_starr's Perl version won't work well for embedded newlines (only copes with spaces). For those on e.g. Solaris where you don't have the GNU tools, a more complete version might be (using sed)...

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

    adjust the find and grep arguments or other commands as you require, but the sed will fix your embedded newlines/spaces/tabs.

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