以下脚本.tex
在目录中搜索带有后缀的文件(即 TeX 文件),查找字符串\RequireLuaTeX
,即该目录中的 LuaTeX 文件,并根据结果创建一个 Bash 数组。
latexmk
然后它对该数组中的文件运行该命令。
我想从此数组中排除用户定义的文件列表,可能声明为数组,因此:
excludedfiles=(foo.tex bar.tex baz.tex)
我写信是为了征求有关干净方法的建议。
我非常喜欢将所有内容放入数组中的方法。一方面,它可以在对文件运行命令之前轻松列出文件。但我愿意考虑其他方法。
#!/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
背景和评论:
TeX 用户可能会对我的问题感到困惑。所以我在这里解释我想要做什么,以及我如何错误地写了这个问题。我不会更改它,因为更改会使现有答案无效并造成混乱。
我有一组 LaTeX 文件。较老的使用 PDFLaTeX。较新的大多使用 PDFLaTeX。这个问题是关于 PDFLaTeX 的。我想在我的脚本中做的是
a) 创建 PDFLaTeX 文件列表。我的 LuaLaTeX 文件中包含字符串“\RequireLuaTeX”。因此,不包含该字符串的文件是 PDFLaTeX 文件。
所以,我试图创建一个 LaTeX 文件列表,其中不包含字符串“\RequireLuaTeX”。
b) 使用 运行 PDFLaTeX latexmk
。
我的问题有以下错误。我写:
以下脚本
.tex
在目录中搜索带有后缀的文件(即 TeX 文件),查找字符串\RequireLuaTeX
,即该目录中的 LuaTeX 文件,并根据结果创建一个 Bash 数组。
事实上,我想要不包含该字符串的文件,因为如上所述,这些文件对应于我的 PDFLaTeX 文件。
答案1
-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[@]}"
**/!(foo|bar|baz).tex
扩展到当前目录树中以 、 或 结尾但.tex
基本名称不是foo.tex
,的所有文件。两个都bar.tex
baz.tex
globstar
和extglob
此操作需要。"${filenames[@]/%.tex/.pdf}"
扩展到数组的所有元素,替换每个元素尾随.tex
经过.pdf
。
由于 Latexmk 可以提供多个文件作为参数,因此我们可以跳过 for 循环。
答案2
使用,您可以通过使用参数扩展标志连接已使用参数扩展标志转义了全局字符的元素,将zsh
数组转换为与其任何元素匹配的模式:|
j[|]
b
#! /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
或者你可以使用e
全局限定符检查t
文件路径的 ail 是否在数组中:
#! /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
答案3
我解决此类问题的方法是将文件名/模式列表转换为具有即时查找而无需搜索的哈希。 (请注意,excludedFiles
诸如 之类的模式z*.tex
将作为赋值的一部分展开,而不是作为散列循环的一部分。例如,如果有三个文件与 glob 匹配z*.tex
,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
答案4
我建议使用一个不带数组的简单 for 循环:
excludedfiles="foo.tex|bar.tex|baz.tex"
for i in $(ls *.tex | egrep -vx ${excludedfiles});do
filename=$(grep -H "\\RequireLuaTeX" $i | awk -F ':' '{print $1}')
base=${filename%.*}
if [[ "$base" == "" ]];then continue; fi
rm -f "$base".pdf
latexmk -pdf -shell-escape -interaction=nonstopmode "$base".tex
done
它能做什么:
- 寻找文件
.tex
- 过滤掉指定的文件(egrep)
- 文本搜索指定模式
\RequireLuaTeX
(“\\”在搜索中包含 \) - 检查空变量
filename
,如果为空则跳到下一个(如果 grep 找不到匹配项,则会发生这种情况) - 使用给定的命令完成
rm
我建议在没有 Final和命令的情况下空运行脚本latex
,并通过 "echo"ing 验证输出"$base"
。我可以想象文件名中的空格问题(对于每个解决方案)。
...
if [[ "$base" == "" ]];then continue; fi
echo $base
done
如果您愿意,您可以提取所有搜索模式并将它们放入变量中,以便更好地调整和轻松处理。