10

I have a bash script that takes a name and a command as arguments. Its pretty simple like this,

#myscript
echo $1
$2

And I run this like this

bash myscripts myjob ls

and it will echo the 'myjob' and run the ls command. But when the command is multi-word, I have to provide it with an inverted commas, like this

bash myscripts myjob "ls -l"

Now my question is, is there a way to write the shell script so that, I don't have to provide the inverted commas? Like, take everything as my command instead of the first argument? Is it possible to do with bash?

Eular
  • 243

1 Answers1

13

Yes, you may use shift to shift previous arguments:

#!/bin/bash
echo "$1"
shift 1
"$@"

shift N will shift the counter so that arguments 1 to N are skipped and argument N+1 is now 1, N+2 is 2, and so on.

Note that this implies that your first command (myjob) is a single-word one and only the second command (ls -l) may be multiple-word.

ilkkachu
  • 138,973
FelixJN
  • 13,566
  • 3
    That $* should be "$@" - otherwise if any of the args is a quoted string containing IFS characters, bash will word split it. e.g. if the 2nd and subsequent are are cp "filename with spaces.txt" "newfile.txt", it will become cp filename with spaces.txt newfile.txt (i.e. there will be four filename args, not two...three source filenames and one target: filename, with, spaces.txt, and newfile.txt). and there'll be even worse problems if any of the args contain shell meta-characters like ; or &. – cas Dec 10 '21 at 14:31
  • @cas Correct and corrected. TY. Detailed reference – FelixJN Dec 10 '21 at 14:34
  • @cas, syntax characters like ;&() shouldn't be an issue when expanding $*, even if it's unquoted. Just IFS characters and glob characters. set -- 'foo;' bar; echo $* works ok and prints foo; bar, but set -- foo "*" bar; echo $* expands the * as a glob. But yes, it should be "$@" here, and even when one needs $*, it should probably be "$*" too. – ilkkachu Dec 10 '21 at 15:21
  • true, i was thinking of eval. – cas Dec 10 '21 at 15:24