当我读到egreg 的 2019 年附录关于如何从 LaTeX 启动 shell 脚本并获取输出。
但是当我尝试使用它连接 SQLite 数据库时,出现了 LaTeX3 错误。以下是(最小)代码:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\captureshell}{som}
{
\sdaau_captureshell:Ne \l__sdaau_captureshell_out_tl { #3 }
\IfBooleanT { #1 }
{% we may need to stringify the result
\tl_set:Nx \l__sdaau_captureshell_out_tl
{ \tl_to_str:N \l__sdaau_captureshell_out_tl }
}
\IfNoValueTF { #2 }
{
\tl_use:N \l__sdaau_captureshell_out_tl
}
{
\tl_set_eq:NN #2 \l__sdaau_captureshell_out_tl
}
}
\tl_new:N \l__sdaau_captureshell_out_tl
\cs_new_protected:Nn \sdaau_captureshell:Nn
{
\sys_get_shell:nnN { #2 } { } #1
\tl_trim_spaces:N #1 % remove leading and trailing spaces
}
\cs_generate_variant:Nn \sdaau_captureshell:Nn { Ne }
\ExplSyntaxOff
\begin{document}
\captureshell{sqlite3 /hom/yannis/texmf/yannis.db 'select title from title where id="grafematik2020/hara/hara.tex"'}
\end{document}
错误说我不允许在 shell 命令中使用双引号:
! LaTeX3 Error: Quotes in shell command 'sqlite3 /hom/yannis/texmf/yannis.db
(LaTeX3) 'select title from title where
(LaTeX3) id="grafematik2020/hara/hara.tex"''.
For immediate help type H <return>.
...
l.34 ... where id="grafematik2020/hara/hara.tex"'}
? H
Shell commands cannot contain quotes (").
如何在 shell 命令行中将字符串嵌套在 SQL 命令中,而不使用双引号?
写出不使用引号的参数值id
违反了 SQL 语法:它会将其视为列名...
[PS:不,我不想使用 LuaTeX 或 Context,尽管我知道它们更适合与 sqlite3 对话。]
答案1
您不能"
在 shell 命令中(直接)使用双引号(ASCII 34),原因与您不能在 web2c TeX 实现(TeX Live、MiKTeX 等)中的文件名中使用双引号的原因相同。
Shell 转义是作为伪文件实现的,因此您使用 I/O 原语(\openin
、、)与 shell 交互,因此所有文件名限制都适用于 shell 命令\write
。\input
Knuth 最初的 TeX 实现不允许在文件名中使用空格(为了更好的理解 :),因为它使用空格作为文件名的终止符。如果您使用原始语法\input
(在 LaTeX 中是\@@input
),您仍然可以看到该实现:
\input my_file.tex text after
上面这一行将输入my_file.tex
,执行其中的任何操作,然后排版text after
。
为了允许在文件名中使用空格,2004 年 Olaf W 在 TeX 中实现了带引号的文件名作为文件系统相关的更改(从而影响了 Knuth TeX),因此您可以输入:
\input "file with spaces.tex" text after
但实现还允许您输入
\input file" "with" "spaces.tex text after
它将删除全部引号,同时保留奇数个引号后的空格。
该实现的问题是,无论如何(即使使用大括号文件名语法),引号都会从文件名中删除,因此目前无法在文件名的任何地方使用引号(因此不能在 shell 命令的任何地方使用引号: expl3
只会阻止您使用该命令,因为如果没有引号,它可能无法按您预期的方式工作)。
也就是说,该限制适用于 TeX 内部处理的文件名。David 的建议应该可以正常工作,因为引号不经过 TeX 的文件名解析:
\newwrite\tmp
\openout\tmp{tmp.sh}
\immediate\write\tmp{ls "/some/path/with spaces/"}
\closeout\tmp
\input{|bash tmp.sh} % \input{"|bash tmp.sh"} if in LaTeX, or your own \captureshell command