我正在编写一个脚本,作为一个"说话终端"(你输入命令,它说输出),到目前为止,我的代码是:
#!/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中工作,并给出预期的输出。任何帮助吗?谢谢,马丁
这是一种罕见的情况,eval
是合适的;您只是在对命令行已经无限制的访问之外加上了一个薄薄的包装。更重要的是,您没有以任何意想不到的方式修改COMMAND
。用户键入什么,将执行什么。
#!/bin/bash
while : ; do
IFS= read -rp "~> " COMMAND
espeak "$(eval "$COMMAND")"
done
注意事项:
-
bash
内置的read
可以使用-p
选项显示自定义提示符。 - 使用
:
或true
命令建立无限循环,这些命令总是成功的。 - 使用
-r
选项,IFS
为空值,以确保COMMAND
被设置为用户输入的精确的行。 - 引用
$COMMAND
,使整个字符串传递给eval
,而不需要任何先前的shell解析。 - 注意,这仍然不能像shell本身那样处理多行输入。(例如,像
for x in 1 2 3; do
这样的行不会提示您输入循环体。)
一个简单的解决方案是使用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
您是否尝试使用"-r"选项?此选项避免解释特殊字符。此外,您必须删除
行中的外部$()espeak "$($COMMAND)"
应该是:
espeak "$(COMMAND)"