2

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

#!/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 中工作并给出预期的输出。有什么帮助吗?谢谢,马丁

4

3 回答 3

2

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

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

几点注意事项:

  1. read内置可以使用该选项bash显示自定义提示。-p
  2. 使用总是成功的:ortrue命令来设置无限循环。
  3. 使用该-r选项和一个空值IFS来确保将COMMAND其设置为用户键入的确切行。
  4. 引用$COMMAND以便传递整个字符串,eval而无需任何先前的 shell 解析。
  5. 请注意,这仍然不能以与 shell 本身相同的方式处理多行输入。(例如,类似的行for x in 1 2 3; do不会提示您输入循环体。)
于 2015-09-28T14:12:20.537 回答
0

一个简单的解决方案是使用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
于 2015-09-28T14:10:04.813 回答
-1

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

espeak "$($COMMAND)"

它应该是:

espeak "$(COMMAND)"
于 2015-09-28T14:22:44.940 回答