Home > Software design >  Correct syntax to combine xargs -i and sh -c?
Correct syntax to combine xargs -i and sh -c?

Time:08-13

I have a file containing a list of null seperated filenames. The output of 'xxd list' is:

00000000: 216d 706f 7373 6962 6c65 0022 4269 675f  !mpossible."Big_
00000010: 5369 7822 5f63 7269 636b 6574 5f64 6973  Six"_cricket_dis
00000020: 7075 7465 5f6f 665f 3139 3132 0022 446f  pute_of_1912."Do
00000030: 6322 5f53 6869 656c 7300 224a 7564 6765  c"_Shiels."Judge
00000040: 5f4a 7564 7922 5f53 6865 696e 646c 696e  _Judy"_Sheindlin
00000050: 0022 4a75 7374 5f79 6f75 725f 4176 6572  ."Just_your_Aver
00000060: 6167 655f 5365 636f 6e64 5f4f 6e5f 5468  age_Second_On_Th
00000070: 6973 5f50 6c61 6e65 7422 5f31 3939 372d  is_Planet"_1997-
00000080: 3139 3938 0022 4b69 6e67 225f 4a6f 655f  1998."King"_Joe_
00000090: 4f6c 6976 6572 0022 4d6f 7468 6572 225f  Oliver."Mother"_
000000a0: 456d 6d61 5f42 7563 6861 6e61 6e00 224e  Emma_Buchanan."N
000000b0: 6f6c 6c79 2200 2250 6570 7065 7222 5f50  olly"."Pepper"_P
000000c0: 6f74 7473 0022 536b 6970 7065 7222 2867  otts."Skipper"(g
000000d0: 616d 655f 6361 6e6e 6f6e 2900            ame_cannon).

When I run the command:

xargs -0 -a list -I{} sh -c "html2text -ascii -o ~/text/{} ./{}"

It produces the following errors:

Cannot open input file "./Doc_Shiels".
Cannot open input file "./Just_your_Average_Second_On_This_Planet_1997-1998".
sh: 1: Syntax error: "(" unexpected

What is the correct syntax to use, to get this to run properly?

CodePudding user response:

When you invoke sh -c "...{}...", the embedded value is inserted as-is.

One of your original values is: "Doc"_Shiels

When you insert it into the command string that will be passed to the shell, you have:

html2text -ascii -o ~/text/{} ./{}

turning into:

html2text -ascii -o ~/text/"Doc"_Shiels ./"Doc"_Shiels

Because the double-quotes are not escaped, they effectively vanish.

Thus your error message.


It is possible to escape your input so that the shell handles it correctly but doing so is error-prone and best avoided.

Instead you can pass the values as arguments:

xargs -0 -a list -I{} \
    sh -c 'html2text -ascii -o ~/text/"$1" ./"$1"' -- {}

POSIX tells us about -c:

sh -c [-abCefhimnuvx] [-o option]... [ abCefhimnuvx] [ o option]...
       command_string [command_name [argument...]]

-c

Read commands from the command_string operand. Set the value of special parameter 0 (see Special Parameters) from the value of the command_name operand and the positional parameters ($1, $2, and so on) in sequence from the remaining argument operands. No commands shall be read from the standard input.

In my example, I have used -- for command_name and {} as a single argument.

Within command_string the argument can be referred to as $1. I have changed the double-quotes to single-quotes so that $1 is not converted too early (ie. not by the shell xargs is running under).

  • Related