Xargs and

Hello there,

Let me show you a simple example of what I am trying to achieve:

1) I have an input text file with some lines:

1 a
2 b
3 c

2) And I want to run a command with these lines as arguments (+ arbitrary extra arguments). For example:

$ command "1 a" "2 b" "3 c" "bye"

I tried with the xargs -I replace-str option, but I didn't succeed. Obviously, we can always write:

$ { cat file; echo "bye"; } | xargs -d"\n" command

I won't say that's ugly, but I feel it may be another smarter solution. Any ideas?

Please test first. and check if this suits you.

awk 'BEGIN{printf "command "}{printf "\"%s\" ",$0}END{printf "bye"}' file | sh

Unless really necessary, I think it's better to avoid "eval" approaches, it can get tricky (i.e. you have to worry about escaping quotes).

Hey, tokland:

To the best of my knowledge, what you seek cannot be done (at least not with the xargs implementations with which I'm familiar, GNU may be another story). The -I and -L options deal with entire lines and pass them as a single argument. The least ugly, portable (-d isn't standardized, if that's of any importance) solution that I can come up with:

echo bye | cat data - | sed 's/ /\\ /g' | xargs command

More or less what you had already come up with. Please post back if you find an elegant solution.

Regards,
Alister

Edit: Do not use the pipeline above. It behaves badly when the space is quoted.

xargs can take input from both a file and arguments at the same time, the downside is that it always puts arguments first, even if you take the "$*" and put it on the end.

xargs -d"\n" command $* < file

This will work for:
command any arguments "1 a" "2 b" "3 c"
but not:
command "1 a" "2 b" "3 c" arguments.

To put arguments on the end, it looks like this is the only option.

echo $* | cat file - | xargs -d"\n" command

Hey, that's a good idea, use cat to join multiple argument sources.

That's right, xargs works perfectly when inserting arguments at the end of the command.

That would work in my example (only one extra argument was used: 'bye'), but multiple arguments would be joined due to the "\n" being the delimiter. This can be easily solved echoing a line for each argument:

for ARG in "4 extra" "5 onemore"; do echo $ARG; done | cat file - | xargs -d"\n" command

Too bad we don't have (AFAIK) a join function (like Python's str.join), we could have written this pretty neat solution:

joinstr -d"\n" "4 extra" "5 onemore" | cat file - | xargs -d"\n" command

Hey, tokland:

Ask and ye shall receive. :wink:

printf '%s\n' "$@" | cat file - | xargs -d"\n" command

That will work fine so long as none of the positional parameters in $@ contain an embedded newline, which is probably an unlikely scenario (all the other solutions in this thread are similarly flawed).

Regards,
Alister

[quote="alister,post:7,topic:261258"]

printf '%s\n' "$@" | cat file - | xargs -d"\n" command

Neat! I didn't know that behavior of printf (from the Bash manual: "format is reused as necessary to consume all of the arguments").

You'll acknowledge, however, that this is not a exact str.join() because it appends the separator at the end. But just about what we needed in this case.

Yes, (tacit) initial assumption was that we don't have newlines in our data domain. That should cover most scenarios (why UNIX allowed newlines in filenames, I'll never know).