10

I'm using xargs to try to echo the name of a file, followed by its contents. Here is the command

find output/ -type f | xargs -I {} sh -c "echo {} ; cat {}"

However for some reason, the second replace after cat is not being replaced. Only for some files, so some files do work correctly.

To be clear, I'm not looking for a command that lets me echo the name of a file followed by its contents, I'm trying to understand why this specific command does not work.

Carlos Bribiescas
  • 4,197
  • 9
  • 35
  • 66

3 Answers3

17

Turns out that the command was too long, so it was working with shorter file names and failing for longer ones. From man xargs

-I replstr
             Execute utility for each input line, replacing one or more occurrences of replstr in up to replacements (or 5 if no -R flag is specified) arguments to utility with the
             entire line of input.  The resulting arguments, after replacement is done, will not be allowed to grow beyond 255 bytes; this is implemented by concatenating as much
             of the argument containing replstr as possible, to the constructed arguments to utility, up to 255 bytes.  The 255 byte limit does not apply to arguments to utility
             which do not contain replstr, and furthermore, no replacement will be done on utility itself.  Implies -x.

ffledgling
  • 11,502
  • 8
  • 47
  • 69
Carlos Bribiescas
  • 4,197
  • 9
  • 35
  • 66
  • 7
    Also from the manpages: -S replsize Specify the amount of space (in bytes) that -I can use for replacements. The default for replsize is 255. I was able to use xargs with a long command by specifying `xargs -S 100000 -I {} `. – Jacob Rodal Jul 28 '21 at 03:21
  • 2
    I dug into this more and learned that I didn't run into a command length issue when running on Linux, only mac os. The manpages I mentioned above are from mac os. – Jacob Rodal Jul 28 '21 at 03:35
4

The root cause of the problem is pointed out in Carlos' answer, but without a solution.

After some googling, I couldn't find a way to lift up the 255 characters limit.

So a probable way to workaround it, is to use shell variable as a substitution.

Example:

find . | xargs -I% sh -c 'F="%";iconv -f gb2312 -t utf-8 "$F">"$F.out";mv "$F.out" "$F"'

Remember to use single quotes at the outermost sh -c parameter string, we don't want the $F inside to be replaced by our parent shell.

ttimasdf
  • 1,367
  • 1
  • 12
  • 19
  • 1
    you can escape the $ in front of a variable to make the subshell fill it instead of the parent shell if you have to use double quotes – Eric Jones Oct 23 '19 at 19:49
2

Is it files with white space in the name that create problems? Try adding \", like this:

find output/ -type f | xargs -I {} sh -c "echo \"{}\" ; cat \"{}\""

This worked for me using Bash.

Mats
  • 101
  • 5