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

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 文件。

Qua*_*odo 7

-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.texbar.tex也不是 的所有文件baz.tex。双方globstarextglob需要进行此项操作。

  • "${filenames[@]/%.tex/.pdf}"扩展到数组的所有元素,将每个尾随 替换.tex.pdf.

由于 Latexmk 可以提供多个文件作为参数,我们可以跳过 for 循环。


Sté*_*las 6

使用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)


roa*_*ima 5

我处理这类问题的方法是将文件名/模式列表转换为一个哈希值,无需搜索即可即时查找。(请注意,excludedFiles诸如此类的模式z*.tex是作为赋值的一部分进行扩展的,而不是作为散列循环的一部分。例如,如果有三个文件与z*.texglob匹配,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)