16

I'd like to count all the ordinary file on home directory with commands:

$ find ~ -type f | xargs echo | wc -w
xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 option

It prompts

xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 option

What's the problem with usage?

2 Answers2

20

It appears that some of your filenames have apostrophes (single quote) in their names.

Luckily, find and xargs have ways around this. find's -print0 option along with xargs's -0 option produce and consume a list of filenames separated by the NUL (\000) character. Filenames in Linux may contain ANY character, EXCEPT NUL and /.

So, what you really want is:

 find ~ -type f -print0 | xargs -0 --no-run-if-empty wc -w

Read man find;man xargs.

waltinator
  • 37,856
2

xargs -d '\n' workaround

For the specific case of find, find -print0 is the best approach as mentioned by waltinator.

But just to satisfy the Google Gods of the Error Message, if your command does not support NUL separation, and if the input also doesn't contain literal newlines, we can also solve the problem by passing -d '\n' to xargs.

For example this attempt to join every two lines fails with the error:

printf "1'\n2\n3\n4\n" | xargs -n2 echo

but we manage to workaround it with:

printf "1'\n2\n3\n4\n" | xargs -d '\n' -n2 echo

which produces the desired output:

1' 2
3 4

man xargs says:

--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.

Related:

Why this error happens

By default printf allows the input to contain arguments with special characters like spaces if they are surrounded by balanced quotes e.g.:

printf "'1 2' 3 4" | xargs -n1 echo

produces:

1 2
3
4

so we understand that the invocations where:

echo 1 2
echo 3
echo 4

Tested on xargs 4.9.0, Ubuntu 24.04.