运行存储在变量中的命令(包括管道和重定向)

时间:2015-09-28 14:01:32

标签: bash shell espeak

我正在编写一个充当"会话终端的脚本" (您输入命令并显示输出)到目前为止我的代码是:

#!/bin/bash
while [ 1=1 ]; do
echo -n "~>"
read COMMAND
espeak "$($COMMAND)"
done

它适用于简单的命令:

bash$ ./talkingterminal.sh
~> ls
# espeak says "talkingterminal.sh"

但是当我使用管道等时:

bash$ ./talkingterminal.sh
~>ip addr | grep inet
Command "|" is unknown, try "ip addr help".
~>

并且该命令在bash中工作并提供预期的输出。 任何帮助? 谢谢, 马丁

3 个答案:

答案 0 :(得分:0)

这是一种罕见的情况eval是合适的;您只需将一个薄的包装器放在已经无限制访问命令行的位置。更重要的是,您不会以任何意外的方式修改COMMAND。用户输入的内容是将要执行的内容。

#!/bin/bash
while : ; do
    IFS= read -rp "~> " COMMAND
    espeak "$(eval "$COMMAND")"
done

一些注意事项:

  1. read内置的bash可以使用-p选项显示自定义提示。
  2. 使用始终成功的:true命令设置无限循环。
  3. 使用-r选项和IFS的空值,确保COMMAND设置为用户输入的完全行。
  4. 引用$COMMAND,以便将整个字符串传递给eval,而不进行任何先前的shell解析。
  5. 请注意,这仍然无法以与shell本身相同的方式处理多行输入。 (例如,像for x in 1 2 3; do这样的行不会提示您输入循环体。)

答案 1 :(得分:-1)

一个简单的解决方案是使用eval

#!/bin/bash
while [ 1=1 ]; do
echo -n "~>"
read COMMAND
espeak "$(eval $COMMAND)"
done

然后您也可以轻松地将输出打印到shell:

#!/bin/bash
while [ 1=1 ]; do
echo -n "~>"
read COMMAND
OUTPUT="$(eval $COMMAND)"
echo $OUTPUT
espeak "$($OUTPUT)"
done

答案 2 :(得分:-1)

您是否尝试过使用“-r”选项?此选项可避免解释特殊字符。此外,您必须删除行中的外部$():

espeak "$($COMMAND)"

应该是:

espeak "$(COMMAND)"