对文件名与模式匹配的文件运行命令,不包括特定的文件列表

对文件名与模式匹配的文件运行命令,不包括特定的文件列表

以下脚本.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.texbaz.texglobstarextglob此操作需要。

  • "${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*.texexcludedFiles则将包含三个条目而不是一个模式,并且散列循环将迭代 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

它能做什么:

  1. 寻找文件.tex
  2. 过滤掉指定的文件(egrep)
  3. 文本搜索指定模式\RequireLuaTeX(“\\”在搜索中包含 \)
  4. 检查空变量filename,如果为空则跳到下一个(如果 grep 找不到匹配项,则会发生这种情况)
  5. 使用给定的命令完成

rm我建议在没有 Final和命令的情况下空运行脚本latex,并通过 "echo"ing 验证输出"$base"。我可以想象文件名中的空格问题(对于每个解决方案)。

...
  if [[ "$base" == "" ]];then continue; fi
  echo $base
done

如果您愿意,您可以提取所有搜索模式并将它们放入变量中,以便更好地调整和轻松处理。

相关内容