How can I use xargs to copy files that have spaces and quotes in their names?
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.
How to return length of string in xargs (special characters)
The problem is not xargs
. The problem is sh
. If you want the correct (unicode) length, you need to use a shell that supports unicode. Observe:
$ echo $a | xargs -rL1 sh -c 'echo ${#0}'
4
$ echo $a | xargs -rL1 bash -c 'echo ${#0}'
3
On debian-like systems, the default shell, /bin/sh
, is actually dash
which does not understand unicode. As shown above, simply replacing sh
with bash
solves the problem.
Escape character ' inside xargs
You may try this xargs
:
xargs -n1 -P8 bash -c "url=\"\$0\"; \
curl -ks -x http://127.0.0.1:8080 -A \"Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0'\" \$url -m 4 1>/dev/null" {} < webs.txt
I'm using xargs, but the argument list is too long
You don't need xargs here, you can do
find . -type f -exec dos2unix '{}' +
Add escapes to special characters in a string (as a function)
Before I attempt to answer, I have a some warnings. I'm not sure what the actual goal is here, so depending on what that is, there are several potential problems.
First, it's impossible in general to reconstruct how a string was quoted/escaped on the command line, because there are many different ways to express the same string in shell syntax. For example, all of the following commands pass exactly the same argument to echo
, and therefore print exactly the same thing:
echo This\ is\ a\ special\ character\ string.\ \\\~\`\!\@\#\$\%\^\&\*\(\)\-\=\+\[\]\{\}\|\;\:\'\"\,\<\>\/\?
echo This\ is\ a\ special\ character\ string.\ \\~\`\!@#\$%^\&*\(\)-=+[]{}\|\;:\'\",\<\>/?
echo 'This is a special character string. \~`!@#$%^&*()-=+[]{}|;:'"'"'",<>/?'
echo $'This is a special character string. \~`!@#$%^&*()-=+[]{}|;:\'",<>/?'
...and many more
(Note: technically, the second of those might pass something different, if the current directory happens to contain one or more files with specific really weird names.)
Second, some versions of echo
do some additional escape processing. Some do this only when passed the -e
option. Some print "-e" if you try to pass the -e
option. It's a mess.
Third, what needs to be escaped and how really depends on what you're going to use it for (and specifically, how it's going to be parsed). Different situations involve different parsing rules, and you have to add escapes appropriate for the specific processing that the output is going to be subject to. In my answer, I concentrated on reversing the specific escaping in your example.
My solution: you can use sed
in a pipeline to add escapes before any of a list of characters, specified as a bracket expression. It's slightly tricky because "]" and "-" are delimiters in a bracket expression; the trick there is to specify "]" as the first character and "-" as the last, so they're not mistaken for their other meanings. Also, I'm going to write this as a single-quoted string, so the single-quote requires special handing. Like this:
sed 's/[][ \~`!@#$%^&*()=+{}|;:'"'"'",<>/?-]/\\&/g'
Or as a function:
addESC() { sed 's/[][ \~`!@#$%^&*()=+{}|;:'"'"'",<>/?-]/\\&/g'; }
Example:
$ echo This\ is\ a\ special\ character\ string.\ \\\~\`\!\@\#\$\%\^\&\*\(\)\-\=\+\[\]\{\}\|\;\:\'\"\,\<\>\/\? | addESC
This\ is\ a\ special\ character\ string.\ \\\~\`\!\@\#\$\%\^\&\*\(\)\-\=\+\[\]\{\}\|\;\:\'\"\,\<\>\/\?
As for why your attempts didn't work: In the first, printf
doesn't read from stdin, it expects arguments. The third tries to fix this with xargs
, but xargs
does its own quote/escape parsing and removal, which messes it up. In the second, <<<
takes a string, not a command; to apply it to the output of a command, you'd use something like <<< "$(command)"
. Also, in all versions, bash printf's %q
quotes and/or escapes specifically as needed for consumption by bash itself, which doesn't match the escaping in your example.
use whitespace as delimiter for xargs arguments
You could use the -d
option to specify the delimiter:
echo 'foo bar' | xargs -I {} -d ' ' sh -c 'echo item: {}'
Will result in:
item: foo
item: bar
--delimiter=delim, -d delim
Input items are terminated by the specified character. The specified delimiter may be a single character, a C-style character escape such as \n, or an octal or hexadecimal escape code. Octal and
hexadecimal escape codes are understood as for the printf command. Multibyte characters are not supported. When processing the input, quotes and backslash are not special; every character in the
input is taken literally. The -d option disables any end-of-file string, which is treated like any other argument. You can use this option when the input consists of simply newline-separated items,
although it is almost always better to design your program to use --null where this is possible.
Make xargs handle filenames that contain spaces
The xargs
command takes white space characters (tabs, spaces, new lines) as delimiters.
You can narrow it down only for the new line characters ('\n') with -d
option like this:
ls *.mp3 | xargs -d '\n' mplayer
It works only with GNU xargs.
For MacOS:
ls *.mp3 | tr \\n \\0 | xargs -0 mplayer
The more simplistic and practically useful approach (when don't need to process the filenames further):
mplayer *.mp3
Related Topics
How to List Recently Deleted Files from a Directory
<Command Line>:1:1: Error: MACro Names Must Be Identifiers
Spell Checking a File Using Command Line, Non-Interactively
How to Install Haskell Platform on Linux Debian Wheezy
Linux Sort Doesn't Work with Negative Float Numbers
How to Remove the Last Character of the Last Line of a File
Comma Separated Values to Single Inverted Quote and Comma Separated Values
Grep Fails Inside Bash Script But Works on Command Line
"Cannot Write to Log File Pg_Upgrade_Internal.Log" When Upgrading from Postgresql 9.1 to 9.3
Add Suffix to Each Line with Shell Script
Sed Permission Denied When Overwriting File
Ignore Case When Trying to Match File Names Using Find Command in Linux