How to store a command in a variable in Linux?

2019-01-02 20:56发布

I would like to store a command to use at a later period in a variable (not the output of the command, but the command itself)

I have a simple script as follows:

command="ls";
echo "Command: $command"; #Output is: Command: ls

b=`$command`;
echo $b; #Output is: public_html REV test... (command worked successfully)

However, when I try something a bit more complicated, it fails. For example, if I make

command="ls | grep -c '^'";

The output is:

Command: ls | grep -c '^'
ls: cannot access |: No such file or directory
ls: cannot access grep: No such file or directory
ls: cannot access '^': No such file or directory

Any idea how I could store such a command (with pipes/multiple commands) in a variable for later use?

4条回答
君临天下
2楼-- · 2019-01-02 20:57

Do not use eval! It has a major risk of introducing arbitrary code execution.

BashFAQ-50 - I'm trying to put a command in a variable, but the complex cases always fail.

Put it in an array and expand all the words with double-quotes "${arr[@]}" to not let the IFS split the words due to Word Splitting.

cmdArgs=()
cmdArgs=('date' '+%H:%M:%S')

and see the contents of the array inside. The declare -p allows you see the contents of the array inside with each command parameter in separate indices. If one such argument contains spaces, quoting inside while adding to the array will prevent it from getting split due to Word-Splitting.

declare -p cmdArgs
declare -a cmdArgs='([0]="date" [1]="+%H:%M:%S")'

and execute the commands as

"${cmdArgs[@]}"
23:15:18

(or) altogether use a bash function to run the command,

cmd() {
   date '+%H:%M:%S'
}

and call the function as just

cmd

POSIX sh has no arrays, so the closest you can come is to build up a list of elements in the positional parameters. Here's a POSIX sh way to run a mail program

# POSIX sh
# Usage: sendto subject address [address ...]
sendto() {
    subject=$1
    shift
    first=1
    for addr; do
        if [ "$first" = 1 ]; then set --; first=0; fi
        set -- "$@" --recipient="$addr"
    done
    if [ "$first" = 1 ]; then
        echo "usage: sendto subject address [address ...]"
        return 1
    fi
    MailTool --subject="$subject" "$@"
}
查看更多
时光乱了年华
3楼-- · 2019-01-02 21:03

Its is not necessary to store commands in variables even as you need to use it later. just execute it as per normal. If you store in variable, you would need some kind of eval statement or invoke some unnecessary shell process to "execute your variable".

查看更多
其实,你不懂
4楼-- · 2019-01-02 21:17
var=$(echo "asdf")
echo $var
# => asdf

Using this method, the command is immediately evaluated and it's return value is stored.

stored_date=$(date)
echo $stored_date
# => Thu Jan 15 10:57:16 EST 2015
# (wait a few seconds)
echo $stored_date
# => Thu Jan 15 10:57:16 EST 2015

Same with backtick

stored_date=`date`
echo $stored_date
# => Thu Jan 15 11:02:19 EST 2015
# (wait a few seconds)
echo $stored_date
# => Thu Jan 15 11:02:19 EST 2015

Using eval in the $(...) will not make it evaluated later

stored_date=$(eval "date")
echo $stored_date
# => Thu Jan 15 11:05:30 EST 2015
# (wait a few seconds)
echo $stored_date
# => Thu Jan 15 11:05:30 EST 2015

Using eval, it is evaluated when eval is used

stored_date="date" # < storing the command itself
echo $(eval $stored_date)
# => Thu Jan 15 11:07:05 EST 2015
# (wait a few seconds)
echo $(eval $stored_date)
# => Thu Jan 15 11:07:16 EST 2015
#                     ^^ Time changed

In the above example, if you need to run a command with arguments, put them in the string you are storing

stored_date="date -u"
# ...

For bash scripts this is rarely relevant, but one last note. Be careful with eval. Eval only strings you control, never strings coming from an untrusted user or built from untrusted user input.

查看更多
时光乱了年华
5楼-- · 2019-01-02 21:24

Use eval:

x="ls | wc"
eval $x
y=$(eval $x)
echo $y
查看更多
登录 后发表回答