Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have a wrapper script that does some work and then passes the original parameters on to another tool:

# ...
other_tool -a -b "$@"

This works fine, unless the "other tool" is run in a subshell:

# ...
bash -c "other_tool -a -b $@"

If I call my wrapper script like this: -x "blah blup"

then, only the first orginal argument (-x) is handed to "other_tool". In reality, I do not create a subshell, but pass the original arguments to a shell on an Android phone, which shouldn't make any difference:

# ...
adb sh -c "other_tool -a -b $@"
share|improve this question
up vote 5 down vote accepted

Bash's printf command has a feature that'll quote/escape/whatever a string, so as long as both the parent and subshell are actually bash, this should work:


quoted_args="$(printf " %q" "$@")" # Note: this will have a leading space before the first arg
# echo "Quoted args:$quoted_args" # Uncomment this to see what it's doing
bash -c "other_tool -a -b$quoted_args"

Note that you can also do it in a single line: bash -c "other_tool -a -b$(printf " %q" "$@")"

share|improve this answer

Change $@ to $*. I did a small local test and it works in my case.

bash -c "echo $*"
bash -c "echo $@"

Saving as and making it executable gives

$ ./ foo bar
foo bar

There is a subtle difference between $* and $@, as you can see. See e.g.

For the follow-up question in the comments: you need to escape e.g. white-space "twice" to pass a string with a separator as a combined argument, e.g. with modified to a wc wrapper:

bash -c "wc $*"

This works:

$ touch test\ file
$ ./ -l "test\ file"
0 test file


$ ./ -l "test file"
wc: test: No such file or directory
wc: file: No such file or directory
0 total
share|improve this answer
Unfortunately, this doesn't work either. If you call the wrapper like this: -x "blah blup" then the subshell gets THREE parameters (-x, blah, blup) instead of TWO (-x, "blah blup") – Ralf Holly Mar 21 '12 at 15:17
You need to "double-escape" the argument if you want the space separator to be preserved, i.e. "Blah\ blup". Try it and see if it works. – Daniel Andersson Mar 21 '12 at 15:22
It looks like it works, however, this would require the caller of to add escapes, and I'm looking for a transparent solution. – Ralf Holly Mar 21 '12 at 15:29

None of the solutions work well. Just pass x/\ \ \"b\"/aaaaa/\'xxx\ yyyy\'/zz\"offf\" as parameter and they fail.

Here is a simple wrapper that handles every case. Note how it escapes each argument twice.

#!/usr/bin/env bash
declare -a ARGS
    ARG="$(printf "%q" "$1")"
    ARGS[INDEX]="$(printf "%q" "$ARG")"

ls -l ${ARGS[*]}
share|improve this answer
also useful if you're trying to concatenate $@ as part of an eventual quoted string argument like '/bin/foo '"$@"' --opt' and discovering that it just doesn't come out as you'd expect. – jrg Jun 17 '14 at 11:22

It's failing because you're coercing an array (the positional parameters) into a string. "$@" is magical because it gives you each separate paramter as a properly quoted string. Adding additional text breaks the magic: "blah $@" is just a single string.

This may get you closer:

cmd="other_tool -a -b"
for parm in "$@"; do cmd+=" '$parm'"; done
adb sh -c "$cmd"

Of course, any parameter that contains a single quote will cause trouble.

share|improve this answer

Ok, more explanashons:

$ cat /tmp/
#! /bin/bash

echo '$@='"$@"

set -v # "debug"

sh -c 'echo $@' "$@" # gremlins steal the first option

sh -c 'echo $@' -- "$@" # We defend the option with two knifes

$ bash -e /tmp/ first second third
$@=first second third

sh -c 'echo $@' "$@" # gremlins steal the first option
second third

sh -c 'echo $@' -- "$@" # We defend the option with two knifes
first second third
share|improve this answer
#! /bin/bash
sh -c 'other_tool -a -b "$@"' -- "$@"
share|improve this answer
Welcome to Super User!  We’re looking for long answers that provide some explanation and context.  Don’t just give a one-line answer; explain why your answer is right, ideally with citations.  Answers that don’t include explanations may be removed. – G-Man May 9 '15 at 6:07

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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