2

I have the following command

echo '123456789#' | xargs -I% bash -c 'echo %%%%%%%%%%%%%%%%%%%%%%%%%'

It doesn't expand the last %. Apparently there's a limit on how long the string passed to bash -c can be. Or maybe it is size of the command that can be passed to xargs? I am curious what kind of constraint is responsible for this behaviour and can it be configured?

Running

echo 'x' | xargs -I% bash -c 'echo %%%%%%%%%%%%%%%%%%%%%%%%%'

gives xxxxxxxxxxxxxxxxxxxxxxxxx so all 25 occurences of % are expanded, which means it's not the number of occurences of %, but rather length of the resulting string

Note: I run this command on MacOS Ventura 13.6.1

New contributor
gicig is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
8
  • 1
    See what-defines-the-maximum-size-for-a-command-single-argument but FWIW I see that string repeated 25 times and less tan 250 chars would be very small for a ARG_MAX setting so you may have something else going on. What happens if you use echo 'x' | xargs ... instead? Do you get 25 xs or not? From testing with other input strings, is the output truncated at 240 chars or 24 repetitions of the input or something else? Or do you see a literal % at the end of the output?
    – Ed Morton
    Commented Jul 1 at 12:36
  • 1
    In general a good practice is not to embed your % in the shell code in the first place. echo '123456789#' | xargs -I% bash -c 'echo "$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1"' bash % Commented Jul 1 at 12:42
  • @EdMorton I get 25 x
    – gicig
    Commented Jul 1 at 12:49
  • 1
    Please edit your question to provide the answers to all of my questions. Don't add information in comments where it can't be formatted and could be missed. Also add the exact output you get from the script you posted. Thanks.
    – Ed Morton
    Commented Jul 1 at 12:53
  • 1
    A portable xargs shall follow this: "At least five arguments in arguments can each contain one or more instances of replstr. Each of these constructed arguments cannot grow larger than an implementation-defined limit greater than or equal to 255 bytes". So maybe it's your xargs that is limited; which is another reason to use the code from my first comment where % gets expanded exactly once and the resulting string is short; then the long string to echo is built in bash, not by xargs. Commented Jul 1 at 13:02

1 Answer 1

1

Linux has a limit of 128 kB for the length of a single argument string, but that's a lot longer a limit than the string you tried. As far as I understand, most other systems have no specific limit for the length of a single argument, but of course have some limits for their total length (it'll have to be limited by available memory anyway, possibly stack space in particular). If Bash itself has a limit, it's likely long enough for all practical purposes.

Se e.g. this should work:

% bash -c "echo $(printf "1234567890%.0s" {0..30}) | rev"
0987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321

The fact that your command leaves some of the %s unexpanded and that it depends on the resulting length, hints at that being an issue of that xargs implementation. (Is it the GNU one? I'm slightly surprised if they have such a low limit.)


In any case, as mentioned in the comments, it's not such a good idea to embed data directly into your shell script as here. It can lead to issues with strange inputs (think quotes), and those can escalate into security problems. Best to avoid doing it.

Instead, pass the data string as an argument to Bash, where it will be available as $1 in the script (the following args being $2, $3 etc).

echo '123456789#' | xargs -I{} bash -c 'echo "$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1"' bash {}

(Note that you still can't pass strings with quotes or backslashes (or that start with whitespace) into that without further consideration, since xargs itself does some quote processing on the input unless you use non-standard options such as the -0 / -d of GNU xargs.)

3
  • I forgot to mention (added that in the question) that I was running that command on MacOS Ventura 13.6.1. I guess there is difference between that implemention and one available on Linux
    – gicig
    Commented Jul 2 at 9:02
  • @gicig, yes, macos has some (possibly old?) version of the FreeBSD toolset, or something like that. They don't support GNU extensions anyway. You just had the question tagged with linux at first, so I guessed at GNU
    – ilkkachu
    Commented Jul 2 at 13:18
  • yes, my mistake, sorry
    – gicig
    Commented 2 days ago

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .