like this:

echo $USER $PASSWORD $RESOURCE_MACHINE $SELECT_SQL  $TARGET_MACHINE $INSERT_SQL | xargs -n6 bash -c '/usr/bin/clickhouse-client -u $1 --password $2 -h $3 -q $4 | /usr/bin/clickhouse-client -u $1 --password $2 -h $5 -q $6' bash

Every argument is a string.

| improve this question | | | | |
  • Do you mean something like this? – Pablo A Dec 31 '19 at 6:54
  • What's the use of xargs in this example? Are you going to have further sets of parameters than the one you're passing with echo? Note that you really need to double quote all variable expansions to avoid word splitting and filename globbing, both for the echo and inside you in-line script. Do any of your values potentially contain spaces or newlines? – Kusalananda Dec 31 '19 at 7:51

xargs' input needs to be formatted in a very specific format. The strings that are to become arguments need to be separated with SPC, TAB, NL (and possibly other whitespace character depending on the xargs implementation and locale), and if any of those characters may occur in the strings, they need to be quoted with single quotes, double quotes or backslash (except for NL that can only be escaped with backslash).

backslash and quotes also need to be escaped. And empty elements have to be enclosed in quotes so as not to be discarded.

So here, you can't use echo to output the list of words in the format recognised by xargs. More generally, echo can't be used to output arbitrary data anyway as it does its own processing of backslashes and/or leading arguments starting with -.

Here, with bash, you could define:

print-for-xargs() {
  local nl=$'\n'
  if (($# > 0)); then
    set -- "${@//\'/\'\\\'\'}"
    printf "'%s'\n" "${@//$nl/\'\\$nl\'}"

That function prints its arguments in the format expected by xargs (putting each argument inside single quotes, with single quotes and newlines themselves quoted with backslash outside of the single-quoted strings).

Then, you can do:

print-for-xargs "$USER" \
                "$PASSWORD" \
                "$RESOURCE_MACHINE" \
                "$SELECT_SQL" \
                "$TARGET_MACHINE" \
                "$INSERT_SQL" |
  xargs -n6 bash -c '
    /usr/bin/clickhouse-client -u "$1" --password "$2" -h "$3" -q "$4" |
      /usr/bin/clickhouse-client -u "$1" --password "$2" -h "$5" -q "$6"
    ' bash

Also remember that parameter expansions have to be quoted in bash like in most other POSIX-like shells.

That's assuming you do need to call xargs for some reason and that you're just showing a simplified example.

Here, you could just do:

  bash -c '
    /usr/bin/clickhouse-client -u "$1" --password "$2" -h "$3" -q "$4" |
      /usr/bin/clickhouse-client -u "$1" --password "$2" -h "$5" -q "$6"

without invoking xargs at all or:

/usr/bin/clickhouse-client -u "$USER" --password "$PASSWORD" \
   /usr/bin/clickhouse-client -u "$USER" --password "$PASSWORD" \

without running a separate instance of a bash interpreter.

Also note that in all those examples, the value of $PASSWORD ends up in the arguments passed to clickhouse-client (and bash for those that run bash) which is bad practice as command arguments are public knowledge locally on a system (they show in the output of ps -f and could end up in audit logs).

| improve this answer | | | | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.