bashshxargs

Redirecting xargs input as stdin stream instead of argument


Sometimes it's useful to write an xargs command that begins with xargs -I {} 'echo {} | [rest of command]' in order to redirect the argument as a pipe.

however, for large arguments, you will encounter xargs: argument line too long.

How do I tell xargs to redirect straight to the os input pipe for [rest of command] so that I avoid the above issue when using large arguments?


Reproducer:

# create a file with very long base64-encoded lines
seq 1 10 |
  xargs -I {} sh -c '
    openssl rand -base64 21000000 | tr -d "'"\n"'"; echo
  '> out.b64

# now, try to pipe each line into a new instance of a program
# xargs fails at doing this because the lines are too large
cat out.b64 |
  xargs -I {} sh -c "echo {} | rest-of-command"

Solution

  • Nothing you're doing calls for xargs at all, anywhere.

    #!/usr/bin/env bash
    
    for ((i=0; i<10; i++)); do
      openssl rand -base64 21000000 | tr -d '\n'
      echo
    done >out.b64
    
    while IFS= read -r line; do
      { rest-of-command; } <<<"$line"
    done <out.b64
    

    The { rest-of-command; } <<<"$line" could also be written as printf '%s\n' "$line" | rest-of-command or < <(printf '%s\n' "$line") rest-of-command. I don't recommend echo for the reasons given in Why is printf better than echo?.

    xargs is a limited-purpose tool: it transports content from stdin to command-line arguments. If that's not what you mean to accomplish, it's the wrong tool for the job.