Sometimes it is necessary to emulate and verify the above variables in small examples and then can be copied immediately to some script, etc.

I tried to solve by using a simple example in the following ways:

(find $1) /tmp
sh -c '(find $1) /tmp'
sh -c "find $1" /tmp
echo '(find $1) /tmp' | sh

and with other combinations. Also experimented by adding the shebang interpreter directive #!/bin/sh -x, but did not get the desired result.

Can I do this simply?

  • 1
    (find $1) /tmp is a syntax error. Actually (any-command) more-arguments is a syntax error. Can you explain differently what you're trying to do?
    – Celada
    Jul 4, 2014 at 15:20
  • 2
    @Celada, it's not a syntax error in shells of the rc family (rc, es, akanga...), where in that case that's equivalent to find $1 /tmp. Jul 4, 2014 at 17:07

2 Answers 2


The first argument after sh -c inline-script goes to $0 (which is also used for error messages), and the rest go in $1, $2...

$ sh -c 'blah; echo "$0"; echo "$1"' my-inline-script arg
my-inline-script: blah: command not found

So you want:

sh -c 'find "$1"' sh /tmp

(in the olden days, you could find sh implementations where the first arg went into $1 instead, so you would do:

sh -c 'find "$1"' /tmp /tmp


sh -c 'shift "$2"; find "$@"' sh 3 2 /tmp1 /tmp2

to account for both behaviours, but those shells are gone now that POSIX is prevalent and publicly available).

If you want to set $1, $2 in a local scope within the current shell, that's where you'd use functions. In Bourne-like shells:

my_func() {
  find "$1"
my_func /tmp

Some shells support anonymous functions. That's the case of zsh:

(){find "$1"} /tmp

Or es:

@{find $1} /tmp

To change the current positional parameters, permanently, the syntax is shell dependant. dchirikov has already covered the Bourne-like shells (Bourne, Korn, bash, zsh, POSIX, ash, yash...).

The syntax is:

set arg1 arg2 ... argn

However, you need:

set --

To empty that list (or shift "$#") and

set -- -foo

to set $1 to something starting with - or +, so it's a good habit to always use set -- especially when using arbitrary data such as set -- "$@" other-arg to add arguments to the end of the positional parameter list.

In shells of the csh family (csh, tcsh), you assign to the argv array:

set argv=(arg1 arg2)

In shells of the rc family (rc, es, akanga), to the * array:

*=(arg1 arg2)

Though you can also assign elements individually:


In fish, the positional parameters are in the argv array only (no $1, $@ there):

set argv arg1 arg2

In zsh, for compatibility with csh, you can also assign to the argv array:

argv=(arg1 arg2)

And you can also do:


That means you can also do things like:


to add an argument to the end, and:


to remove an argument from the end or the middle, which you can't easily do with other shells.

set --

is what you need:

$ set -- aaa bbb ccc
$ echo "$1"
$ echo "$2"
$ echo "$3"
$ echo "$@"
aaa bbb ccc

You must log in to answer this question.

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