Fah*_*tha 7 scripting bash shell-script
以下脚本.tex
在目录中搜索带有后缀的文件(即 TeX 文件),以查找字符串\RequireLuaTeX
,即该目录中的 LuaTeX 文件,并根据结果创建一个 Bash 数组。
然后它latexmk
对该数组中的文件运行该命令。
我想从这个数组中排除一个用户定义的文件列表,可能声明为一个数组,因此:
excludedfiles=(foo.tex bar.tex baz.tex)
Run Code Online (Sandbox Code Playgroud)
我写信是为了征求关于干净的方法的建议。
我非常喜欢把所有东西都放在一个数组中的方法。一方面,它可以在对文件运行命令之前轻松列出文件。但我愿意考虑其他方法。
#!/bin/bash
## Get LuaTeX filenames
mapfile -t -d "" filenames < <(grep -Z -rL "\RequireLuaTeX" *.tex)
## Run `latexmk` on PDFTeX files.
for filename in "${filenames[@]}"
do
base="${filename%.*}"
rm -f "$base".pdf
latexmk -pdf -shell-escape -interaction=nonstopmode "$base".tex
done
Run Code Online (Sandbox Code Playgroud)
背景和评论:
TeX 用户可能对我的问题感到困惑。所以我在这里解释我想要做什么,以及我是如何错误地写这个问题的。我不会更改它,因为更改会使现有答案无效并造成混乱。
我有一组 LaTeX 文件。较旧的使用 PDFLaTeX。较新的主要使用 PDFLaTeX。这个问题是关于 PDFLaTeX 的。我想在我的脚本中做的是
a) 创建一个 PDFLaTeX 文件列表。我的 LuaLaTeX 文件中包含字符串“\RequireLuaTeX”。因此,不包含该字符串的文件是 PDFLaTeX 文件。
所以,我试图创建一个 LaTeX 文件列表,其中不包含字符串“\RequireLuaTeX”。
b) 使用latexmk
.
我的问题有以下错误。我写:
以下脚本
.tex
在目录中搜索带有后缀的文件(即 TeX 文件),以查找字符串\RequireLuaTeX
,即该目录中的 LuaTeX 文件,并根据结果创建一个 Bash 数组。
事实上,我想要不包含该字符串的文件,因为如上所述,那些对应于我的 PDFLaTeX 文件。
-L
标记为不匹配模式的 Grep 列表文件。你想要-l
。此外,Grep 需要看到双反斜杠以匹配单个反斜杠。
由于您使用的是 Bash,让我们掌握一些有用的构造。
#!/bin/bash -
shopt -s globstar extglob
mapfile -t -d "" filenames < <(grep -Zl '\\RequireLuaTeX' ./**/!(foo|bar|baz).tex)
rm -f "${filenames[@]/%.tex/.pdf}"
latexmk -pdf -shell-escape -interaction=nonstopmode "${filenames[@]}"
Run Code Online (Sandbox Code Playgroud)
**/!(foo|bar|baz).tex
扩展到当前目录树中以 结尾.tex
但基本名称不是foo.tex
,bar.tex
也不是 的所有文件baz.tex
。双方globstar
并extglob
需要进行此项操作。
"${filenames[@]/%.tex/.pdf}"
扩展到数组的所有元素,将每个尾随 替换.tex
为.pdf
.
由于 Latexmk 可以提供多个文件作为参数,我们可以跳过 for 循环。
使用zsh
,您可以通过|
使用j[|]
参数扩展标志连接其中已使用b
参数扩展标志转义 glob 字符的元素,将数组转换为匹配其任何元素的模式:
#! /bin/zsh -
set -o extendedglob
excluded_file_names=(foo.tex bar.tex baz.tex)
excluded_file_names_pattern="(${(j[|])${(@b)excluded_file_names}})"
# here using the ~ extendedglob operator to apply the exclusion
tex_files=(
./**/(*.tex~$~excluded_file_names_pattern)
)
files=(
${(0)"$(grep -lZF '\RequireLuaTeX' $tex_files)"}
)
rm -f ${files/%tex/pdf}
latexmk -pdf -shell-escape -interaction=nonstopmode $files
Run Code Online (Sandbox Code Playgroud)
或者您可以使用e
glob 限定符来检查t
文件路径的所有内容是否在数组中:
#! /bin/zsh -
excluded_file_names=(foo.tex bar.tex baz.tex)
tex_files=(
./**/*.tex(^e['(($excluded_file_names[(Ie)$REPLY:t]))'])
)
files=(
${(0)"$(grep -lZF '\RequireLuaTeX' $tex_files)"}
)
rm -f ${files/%tex/pdf}
latexmk -pdf -shell-escape -interaction=nonstopmode $files
Run Code Online (Sandbox Code Playgroud)
我处理这类问题的方法是将文件名/模式列表转换为一个哈希值,无需搜索即可即时查找。(请注意,excludedFiles
诸如此类的模式z*.tex
是作为赋值的一部分进行扩展的,而不是作为散列循环的一部分。例如,如果有三个文件与z*.tex
glob匹配,excludedFiles
则将包含三个条目而不是一个模式,并且散列循环将迭代 3 次。)
# User configurable list of files and patterns
excludedFiles=(foo.tex bar.tex baz.tex z*.tex)
# Convert the list into a hash
declare -A excludedHash
for excludedFile in "${excludedFiles[@]}"
do
[[ -e "$excludedFile" ]] && excludedHash[$excludedFile]=yes
done
# Processing
for filename in "${filenames[@]}"
do
[[ -n "${excludedHash[$filename]}" ]] && continue # Skip if filename is in hash
base="${filename%.*}"
rm -f "$base".pdf
latexmk -pdf -shell-escape -interaction=nonstopmode "$base".tex
done
Run Code Online (Sandbox Code Playgroud)