taalf
taalf

Reputation: 179

Bash: execute a multi-command line string in a script

There is, in a file, some multi-command line like this:

cd /home/user; ls

In a bash script, I would like to execute these commands, adding some arguments to the last one. For example:

cd /home/user; ls   -l *.png

I thought it would be enough to do something like this:

#!/bin/bash
commandLine="$(cat theFileWithCommandInside)   -l *.png"
$commandLine
exit 0

But it says:

/home/user;: No such file or directory

In other words, the ";" character doesn't mean anymore "end of the command": The shell is trying to find a directory called "user;" in the home folder...

I tried to replace ";" with "&&", but the result is the same.

Upvotes: 3

Views: 2531

Answers (5)

atul
atul

Reputation: 61

Using the <(...) form

sh <(sed 's/$/ *.png/' theFileWithCommandInside)

Upvotes: 0

taalf
taalf

Reputation: 179

The key is: eval

Here, the fixed script (look at the third line):

#!/bin/bash
commandLine="$(cat theFileWithCommandInside)   -l *.png"
eval $commandLine
exit 0

Upvotes: 2

Jason Hu
Jason Hu

Reputation: 6333

the point of your question is to execute command stored in string. there are thousands of ways to execute that indirectly. but eventually, bash has to involve.

so why not explicitly invoke bash to do the job?

bash -c "$commandLine"

from doc:

-c string

If the -c option is present, then commands are read from string. If there are arguments after the string, they are assigned to the positional parameters, starting with $0.

http://linux.die.net/man/1/bash

Upvotes: 3

Michael Jaros
Michael Jaros

Reputation: 4681

Wrap the command into a function:

function doLS() {
    cd user; ls $@
}

$@ expands to all arguments passed to the function. If you (or the snippet authors) add functions expecting a predefined number of arguments, you may find the positional parameters $1, $2, ... useful instead.

As the maintainer of the main script, you will have to make sure that everyone providing such a snippet provides that "interface" your code uses (i.e. their code defines the functions your program calls and their functions process the arguments your program passes).

Use source or . to import the function into your running shell:

#!/bin/bash
source theFileWithCommandInside
doLS -l *.png
exit 0

I'd like to add a few thoughts on the ; topic:

In other words, the ";" character doesn't mean anymore "end of the command": The shell is trying to find a directory called "user;" in the home folder...

; is not used to terminate a statement as in C-style languages. Instead it is used to separate commands that should be executed sequentially inside a list. Example executing two commands in a subshell:

( command1 ; command2 )

If the list is part of a group, it must be succeeded by a ;:

{ command1 ; command2 ; }

In your example, tokenization and globbing (replacing the *) will not be executed (as you may have expected), so your code will not be run successfully.

Upvotes: 2

Dragan
Dragan

Reputation: 455

Why dont you execute the commands themselves in the script, instead of "importing" them?

#!/bin/bash
cd /home/user; ls -l *.png
exit 0

Upvotes: 2

Related Questions