Linux 如何将命令存储在 shell 脚本的变量中?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5615717/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 00:39:04  来源:igfitidea点击:

How to store a command in a variable in a shell script?

linuxbashvariablescommand

提问by Benjamin

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?

知道如何将这样的命令(带有管道/多个命令)存储在变量中供以后使用吗?

采纳答案by Erik

Use eval:

使用评估:

x="ls | wc"
eval "$x"
y=$(eval "$x")
echo "$y"

回答by kurumi

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 evalstatement or invoke some unnecessary shell process to "execute your variable".

即使您以后需要使用它,也没有必要将命令存储在变量中。只需按正常方式执行即可。如果您存储在变量中,您将需要某种eval语句或调用一些不必要的 shell 进程来“执行您的变量”。

回答by Nate

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

在 the 中使用 eval$(...)不会让它稍后被评估

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 evalis used

使用 eval,在eval使用时进行评估

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.

对于 bash 脚本,这很少相关,但最后一个注意事项。小心eval. 仅评估您控制的字符串,而不是来自不受信任的用户或根据不受信任的用户输入构建的字符串。

  • Thanks to @CharlesDuffy for reminding me to quote the command!
  • 感谢@CharlesDuffy 提醒我引用命令!

回答by Inian

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

千万不能使用eval!它具有引入任意代码执行的主要风险。

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

BashFAQ-50- 我试图将命令放入变量中,但复杂的情况总是失败。

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

把它放在一个阵列,并展开所有用双引号的话"${arr[@]}"没有IFS分裂由于单词分词

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

and see the contents of the array inside. The declare -pallows 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允许你看到阵列内的内容物与单独的索引每个命令参数。如果一个这样的参数包含空格,则在添加到数组时引用内部将防止它由于分词而被拆分。

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 bashfunction to run the command,

(或)完全使用一个bash函数来运行命令,

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

and call the function as just

并调用该函数

cmd

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

POSIXsh没有数组,所以最接近的是在位置参数中建立一个元素列表。这是sh运行邮件程序的 POSIX方式

# POSIX sh
# Usage: sendto subject address [address ...]
sendto() {
    subject=
    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" "$@"
}

Note that this approach can only handle simple commands with no redirections. It can't handle redirections, pipelines, for/while loops, if statements, etc

请注意,这种方法只能处理没有重定向的简单命令。它无法处理重定向、管道、for/while 循环、if 语句等

Another common use case is when running curlwith multiple header fields and payload. You can always define args like below and invoke curlon the expanded array content

另一个常见用例是curl使用多个标头字段和有效负载运行时。您始终可以像下面这样定义 args 并调用curl扩展的数组内容

curlArgs=('-H' "keyheader: value" '-H' "2ndkeyheader: 2ndvalue")
curl "${curlArgs[@]}"

Another example,

另一个例子,

payload='{}'
hostURL='http://google.com'
authToken='someToken'
authHeader='Authorization:Bearer "'"$authToken"'"'

now that variables are defined, use an array to store your command args

现在定义了变量,使用数组来存储您的命令参数

curlCMD=(-X POST "$hostURL" --data "$payload" -H "Content-Type:application/json" -H "$authHeader")

and now do a proper quoted expansion

现在做一个适当的引用扩展

curl "${curlCMD[@]}"

回答by Derek Hazell

For bash, store your command like this:

对于 bash,像这样存储你的命令:

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

Run your command like this:

像这样运行你的命令:

echo $command | bash

回答by mpen

I tried various different methods:

我尝试了各种不同的方法:

printexec() {
  printf -- "3[1;37m$3[0m"
  printf -- " %q" "$@"
  printf -- "\n"
  eval -- "$@"
  eval -- "$*"
  "$@"
  "$*"
}

Output:

输出:

$ printexec echo  -e "foo\n" bar
$ echo -e foo\n bar
foon bar
foon bar
foo
 bar
bash: echo -e foo\n bar: command not found

As you can see, only the third one, "$@"gave the correct result.

如您所见,只有第三个"$@"给出了正确的结果。

回答by Azerty

Be Careful registering an order with the: X=$(Command)

小心注册订单: X=$(Command)

This one is still executed Even before being called. To check and confirm this, you cand do:

即使在被调用之前,这个仍然被执行。要检查并确认这一点,您可以执行以下操作:

echo test;
X=$(for ((c=0; c<=5; c++)); do
sleep 2;
done);
echo note the 5 seconds elapsed