在 《每天进步一点点:学习使用Graphviz》一文中,我介绍了初学者了解&使用graphviz最简便的方法,那就是直接使用命令行。
(图源 :pixabay)
比如,最简单的生成最简单的“Hello World”关系图,命令如下:
echo 'digraph { Hello -> World }' | dot -Tsvg > output.svg
但是这条命令在Linux下或许会准确无误地执行,在Windows下,却只生成了一个0字节大小的svg文件,内容嘛,自不必多言,当然是空的。
好吧,我还曾试图打开它,得到如下提示信息:
This XML file does not appear to have any style information associated with it. The document tree is shown below.
从代码上,貌似并没有什么问题呀?哪里出错了呢?上述代码的意义就是将echo语句的输出作为输入传递给dot指令,然后在把输出重定向给output.svg。
其中涉及到输入输出重定向的两个操作分别为|
(管道操作符)以及>
(输出重定向),想对这个两个深入了解的请参考文末链接。
既然我们不清楚哪里出错,那么就逐步调试呗,我们首先测试管道前边的部分,echo 'digraph { Hello -> World }'
,期望其输出digraph { Hello -> World }
。
然而在Windows命令行执行上述指令,却发现什么输出都没有。
仔细研究会发现在语句echo 'digraph { Hello -> World }'
中>
被识别为输出重定向,它把ECHO输出的内容,重定向到一个名为World的文件中,这显然不是我们需要的结果。
测试使用转义字符^
来对>
进行转义,亦即echo 'digraph { Hello -^> World }'
,倒是可以输出'digraph { Hello -> World }'
,但是传递给dot依然失败,果断放弃。
这时我想到,既然单引号中的内容会被转义,那么如果使用双引号呢?亦即echo "digraph { Hello -> World }" | dot -Tsvg > output.svg
结果却得到如下提示:
Error: <stdin>: syntax error in line 1 near '"'
看一下echo语句的输出,为"digraph { Hello -> World }"
,也就是说dot程序不接受""
(双引号)作为输入(可以直接执行dot -Tsvg
,并输入上述内容验证)。
现在,问题进一步简化,就变成了,如何脱掉echo输出中的双引号。
原本以为这并不会是个问题,毕竟Linux下echo支持很多参数,而且输出的内容直接是脱双引号的,结果折腾半天才发现,Windows的echo弱到爆!指望参数啥的来搞定,那是不可能啦。
通过参数转换去双引号
经过我不懈努力,找到几个去掉双引号的方案,多数是使用批处理文件调用时通过去掉参数的双引号来实现的:
%~1 Expands %1 and removes surrounding quotation marks.
比如以下这个例子(来自文末链接):
@echo off
setlocal
set mystring="this is some quoted text"
echo mystring=%mystring%
call :dequote %mystring%
echo ret=%ret%
endlocal
goto :eof
:dequote
setlocal
rem The tilde in the next line is the really important bit.
set thestring=%~1
endlocal&set ret=%thestring%
goto :eof
但是我们把代码中字符串换成我们需要的"digraph { Hello -> World }"
,输出却不是我们想要的样子:
其实对于上述代码,我们可以简化成如下形式:
@setlocal
@set thestring=%~1
@echo %thestring%
@endlocal
将其保存为myecho.bat,并以类似如下形式调用:
myecho "digraph { Hello }" | dot
是可以得到正确输出的
但是依然无法正确处理"digraph { Hello -> World }"
。
通过搜索替换去双引号
另一种方案是通过搜索替换来去掉双引号。
其本质是基于可以使用%var:x=y%构造将所有x替换为y
示例代码如下(来自文末链接):
set I="Text in quotes"
rem next line replaces" with blanks
set J=%I:"=%
echo original %I%
rem next line replaces the string 'in' with the string 'without'
echo stripped %J:in=without%
代码不做更多解读了,同样处理不了我们的问题。
通过set的提示语
无意中又发现一种方案,这个就太牛了,示例如下:
echo | set /p=";lt;h1;gt;Hello;lt;/h1;gt;"
输出如下:
这段代码我敢保证99%的人看不懂。
我们通过set /?
来查看以下帮助信息(部分内容如下):
我们会发现/p
的作用是带出一串提示信息,然后手动输入从终端变量值。这时候echo
以及|
(管道操作)起的作用是模拟终端输入回车。
如果后边继续跟|
,那么会因为没有额外输入信息,所以提示信息被作为输入传递给之后的程序。
所以以下语句是可以正常工作的:
echo | set /p="digraph { Hello -> World }"| dot -Tsvg > output.svg
我们会得到如下图形:
也可以使用如下语句调试一下:
echo | set /p="digraph { Hello -> World }"| dot
不得不感慨一下,互联网上真的有能人啊!我去理解都费了如此周转,那么这是什么脑回路才能想出来的办法?
然后又不得不感慨一下自己,得多么无聊地浪费大把的时间研究这个?明明只有初学者测试才能用到命令行直接echo
的方式。还有就是既然Windows的echo不好用,写一个简单的echo,大概也用不了多久吧!
又是虚度光阴的一整天!😡
相关链接
- 每天进步一点点:学习使用Graphviz
- 如何在Windows批处理文件的ECHOed字符串中去除引号?
- windows - 如何从 Windows 批处理文件中的 ECHO 字符串中去除引号?
- https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/echo
- https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/call
- https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/set_1
- https://ss64.com/nt/set.html
- https://ss64.com/nt/syntax-args.html
- https://ss64.com/nt/syntax-redirection.html