9

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 '14 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. – Stéphane Chazelas Jul 4 '14 at 17:07
15

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
my-inline-script
arg

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

Or:

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:

2=arg2

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)
argv[4]=arg4

And you can also do:

5=arg5

That means you can also do things like:

argv+=(another-arg)

to add an argument to the end, and:

argv[-1]=()
argv[2]=()

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

7
set --

is what you need:

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

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.