我将尝试在Bash中实现 REPL(读取-求值-输出循环)。如果已经存在这样的东西,请忽略以下内容,并使用指向它的指针回答此问题。
让我们以这个脚本为例(将其命名为
我想做的是逐行读取此脚本,检查我已经读到的内容是否是完整的bash表达式;如果它是完整的,则
我想要实现的输出是这样的:
让我们以这个脚本为例(将其命名为
test.sh
):if true
then
echo a
else
echo b
fi
echo c
我想做的是逐行读取此脚本,检查我已经读到的内容是否是完整的bash表达式;如果它是完整的,则
eval
它;否则继续读取下一行。下面的脚本希望能够说明我的想法(尽管它并不完全有效)。x=""
while read -r line
do
x=$x$'\n'$line # concatenate by \n
# the line below is certainly a bad way to go
if eval $x 2>/dev/null; then
eval $x # code seems to be working, so eval it
x="" # empty x, and start collecting code again
else
echo 'incomplete expression'
fi
done < test.sh
动机
对于一个bash脚本,我希望将其解析为语法完整的表达式,评估每个表达式,捕获输出,并最终标记源代码和输出(例如使用Markdown/HTML/LaTeX/...)。例如,对于一个脚本:
echo a
echo b
我想要实现的输出是这样的:
```bash
echo a
```
```
a
```
```bash
echo b
```
```
b
```
不要评估整个脚本并捕获所有输出:
```bash
echo a
echo b
```
```
a
b
```
sh -n secondscript.sh
。祝你好运。 - shellterbash -nc "$x"
并捕获stderr
;如果该命令成功运行,则$x
可能是语法上有效的。否则,如果stderr
包含“syntax error: unexpected end of file”(在英语环境中),则该命令可能不完整,您可以添加下一行。其他语法错误不能通过添加更多标记来解决,因此您应该输出语法错误(可能是通过重新输出捕获的stderr
实现)。 - ricieval
,以防第二个eval
复制了副作用。其次,你可以使用x+=$'\n'$line
更简洁地进行字符串拼接。第三点,请注意,你不能像这样逐行评估多行语句(例如完整的if
语句或循环)。 - chepnereval
存在太多的边角案例和可能的故障,让我头晕...唯一正确的方法是使用bash的词法分析器,并通过它运行语句。例如,如果你不反对使用Python,pygments有一个针对bash的词法分析器。 - John