![](/img/trans.png)
[英]How can I store the result of this command as a variable in my bash script?
[英]How can I store a command in a variable in a shell script?
我想将一个命令存储在一个变量中以便稍后使用(不是命令的 output,而是命令本身)。
我有一个简单的脚本如下:
command="ls";
echo "Command: $command"; #Output is: Command: ls
b=`$command`;
echo $b; #Output is: public_html REV test... (command worked successfully)
但是,当我尝试更复杂的东西时,它失败了。 例如,如果我让
command="ls | grep -c '^'";
output 是:
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
我如何将这样的命令(使用管道/多个命令)存储在变量中供以后使用?
使用评估:
x="ls | wc"
eval "$x"
y=$(eval "$x")
echo "$y"
不要使用eval
! 它具有引入任意代码执行的主要风险。
把它放在一个数组中,并用双引号"${arr[@]}"
展开所有单词,以免IFS
由于Word Splitting而拆分单词。
cmdArgs=()
cmdArgs=('date' '+%H:%M:%S')
并查看里面数组的内容。 declare -p
允许您使用单独索引中的每个命令参数查看内部数组的内容。 如果一个这样的参数包含空格,则在添加到数组时引用内部将防止它由于分词而被拆分。
declare -p cmdArgs
declare -a cmdArgs='([0]="date" [1]="+%H:%M:%S")'
并执行命令
"${cmdArgs[@]}"
23:15:18
(或)完全使用bash
函数来运行命令,
cmd() {
date '+%H:%M:%S'
}
并调用该函数
cmd
POSIX sh
没有数组,所以最接近的是在位置参数中建立一个元素列表。 这是运行邮件程序的 POSIX sh
方式
# 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" "$@"
}
请注意,这种方法只能处理没有重定向的简单命令。 它无法处理重定向、管道、for/while 循环、if 语句等
另一个常见用例是使用多个标头字段和有效负载运行curl
。 您始终可以像下面这样定义参数并在扩展的数组内容上调用curl
curlArgs=('-H' "keyheader: value" '-H' "2ndkeyheader: 2ndvalue")
curl "${curlArgs[@]}"
另一个例子,
payload='{}'
hostURL='http://google.com'
authToken='someToken'
authHeader='Authorization:Bearer "'"$authToken"'"'
现在定义了变量,使用数组来存储您的命令参数
curlCMD=(-X POST "$hostURL" --data "$payload" -H "Content-Type:application/json" -H "$authHeader")
现在做一个适当的引用扩展
curl "${curlCMD[@]}"
var=$(echo "asdf")
echo $var
# => asdf
使用这种方法,命令会立即被评估并存储它的返回值。
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
与反引号相同
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
在$(...)
使用 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
使用eval,在使用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
在上面的例子中,如果你需要运行一个带参数的命令,把它们放在你存储的字符串中
stored_date="date -u"
# ...
对于 bash 脚本,这很少相关,但最后一个注意事项。 小心eval
。 仅评估您控制的字符串,而不是来自不受信任的用户或根据不受信任的用户输入构建的字符串。
对于 bash,像这样存储你的命令:
command="ls | grep -c '^'"
像这样运行你的命令:
echo $command | bash
我尝试了各种不同的方法:
printexec() {
printf -- "\033[1;37m$\033[0m"
printf -- " %q" "$@"
printf -- "\n"
eval -- "$@"
eval -- "$*"
"$@"
"$*"
}
输出:
$ 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
如您所见,只有第三个"$@"
给出了正确的结果。
不知道为什么这么多答案使它变得复杂! 使用 alia [command] 'string to execute' 示例:
alias dir='ls -l'
./dir
[pretty list of files]
我用以下命令遇到了这个问题:
awk '{printf "%s[%s]\n", $1, $3}' "input.txt"
我需要动态构建这个命令:
目标文件名input.txt
是动态的,可能包含空格。
{}
大括号内的awk
脚本printf "%s[%s]\n", $1, $3
是动态的。
awk
脚本中有很多"
,请避免大量引用 escaping 逻辑。$
字段变量进行参数扩展。 下面使用eval
命令和关联arrays
的解决方案不起作用。 由于bash
变量扩展和引用。
动态构建bash
变量,避免bash
扩展,使用printf
模板。
# dynamic variables, values change at runtime.
input="input file 1.txt"
awk_script='printf "%s[%s]\n" ,$1 ,$3'
# static command template, preventing double-quote escapes and avoid variable expansions.
awk_command=$(printf "awk '{%s}' \"%s\"\n" "$awk_script" "$input")
echo "awk_command=$awk_command"
awk_command=awk '{printf "%s[%s]\n" ,$1 ,$3}' "input file 1.txt"
bash -c "$awk_command"
也有效的替代方案
bash << $awk_command
由于您没有指定任何脚本语言,因此我会推荐tcl
,用于这种目的的工具命令语言。
然后在第一行,添加适当的 shebang:
#!/usr/local/bin/tclsh
在适当的位置,您可以使用which tclsh
检索。
在tcl
脚本中,您可以使用exec
调用操作系统命令。
使用以下命令小心注册订单: X=$(Command)
即使在被调用之前,这个仍然被执行。 要检查并确认这一点,您可以执行以下操作:
echo test;
X=$(for ((c=0; c<=5; c++)); do
sleep 2;
done);
echo note the 5 seconds elapsed
首先,有这方面的功能。 但是如果你更喜欢 vars 那么你的任务可以这样完成:
$ cmd=ls
$ $cmd # works
file file2 test
$ cmd='ls | grep file'
$ $cmd # not works
ls: cannot access '|': No such file or directory
ls: cannot access 'grep': No such file or directory
file
$ bash -c $cmd # works
file file2 test
$ bash -c "$cmd" # also works
file
file2
$ bash <<< $cmd
file
file2
$ bash <<< "$cmd"
file
file2
或者通过 tmp 文件
$ tmp=$(mktemp)
$ echo "$cmd" > "$tmp"
$ chmod +x "$tmp"
$ "$tmp"
file
file2
$ rm "$tmp"
#!/bin/bash
#Note: this script works only when u use Bash. So, don't remove the first line.
TUNECOUNT=$(ifconfig |grep -c -o tune0) #Some command with "Grep".
echo $TUNECOUNT #This will return 0
#if you don't have tune0 interface.
#Or count of installed tune0 interfaces.
即使您以后需要使用它,也没有必要将命令存储在变量中。 只需按正常方式执行即可。 如果您存储在变量中,您将需要某种eval
语句或调用一些不必要的 shell 进程来“执行您的变量”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.