如何以最小、DRY、漂亮的方式执行同一目录中的多个文件?

如何以最小、DRY、漂亮的方式执行同一目录中的多个文件?

我使用 Ubuntu 16.04,我有一个本地化文件,一个执行许多文件的文件,是我将自己的 GitHub 项目下载到我的计算机后获得的。

该文件包含一个 Bash 脚本,名为localize.sh.我通过在子会话中运行它~/${repo}/localize.sh

该文件包含许多行,所有行都具有相同的基本模式(见下文),以在子会话中执行所有相关文件。

这是该文件的实际内容:

#!/bin/bash
~/${repo}/apt/security.sh
~/${repo}/apt/lemp.sh
~/${repo}/apt/certbot.sh
~/${repo}/apt/misc.sh

~/${repo}/third-party/pma.sh
~/${repo}/third-party/wp-cli.sh

~/${repo}/conf/nginx.sh
~/${repo}/conf/php.sh
~/${repo}/conf/crontab.sh

~/${repo}/local/tdm.sh

人们可以注意到重复的~/${repo}/模式。

这不是一个大问题,但减少这些冗余字符仍然是件好事,因为该文件应该变得更大。

实现 DRY 的最简单方法是什么(不要重复自己该代码的版本?

在这种情况下,我个人不想使用一根长线。

编辑:原则上,除了 .txt 中列出的文件之外,列出的目录中不存在也不应该存在任何其他文件localize.sh


localize.sh另外,名称以及调用文件的操作可能localization是一个不好的方法;如果您认为写得不好,请批评我,请在旁注中指出。

答案1

不清楚你是否在跑步全部相关目录中的脚本,但如果是的话,您可能会发现run-parts有用:

for subdir in apt third-party conf local
do
    run-parts --regex '\.sh$' ~/${repo}/${subdir}
done

请注意,这将在每个目录中按字母数字顺序运行脚本,因此如果子目录中的顺序很重要,您将需要重命名它们(或对它们进行编号)。您可以run-parts通过使用以下选项运行它来提前查看将要执行的操作--test

apt/certbot.sh
apt/lemp.sh
apt/misc.sh
apt/security.sh
third-party/pma.sh
third-party/wp-cli.sh
conf/crontab.sh
conf/nginx.sh
conf/php.sh
local/tdm.sh

答案2

简单而简短的“find ${repo} -exec {} \;”怎么样?

我的示例脚本只是回显“foo”或“bar”或“baz”:

$ repo=~/scripts/bash/foo; find ${repo} -type f -iname "*.sh" -exec {} \;
foo
baz
bar

你甚至可以使用别名'来缩短它:

$ alias run_myscripts='repo=~/scripts/bash/foo; find ${repo} -type f -iname "*.sh" -exec {} \;'

或 $ alias run_myscripts='find ~/scripts/bash/foo -type f -iname "*.sh" -exec {} \;'

然后运行

run_myscripts

只是注意到文件需要执行标志。如果他们没有或者您不确定,您只需扩展“find ... -exec”命令,如下所示:

find ${repo} -type f -iname "*.sh" -exec bash {} \;'

编辑:好的,没有注意到应该保留订单。这会稍微改变它,我认为一个好方法是将订单放入文本文件中,并在执行行周围包裹一个“读取行”。

while read line; do 
    bash ~/${repo}/$line
done < ordered_scripts.txt 

在ordered_scripts.txt中,您可以定义正确的顺序。

apt/security.sh
apt/lemp.sh
apt/certbot.sh
apt/misc.sh
third-party/pma.sh
third-party/wp-cli.sh
conf/nginx.sh
conf/php.sh
conf/crontab.sh
local/tdm.sh

答案3

假设所有脚本都位于公共父目录中,~/${repo}您可以将它们放入一个数组中并对其进行循环:

SCRIPTS=(apt/security.sh apt/lemp.sh apt/certbot.sh apt/misc.sh
         tp/pma.sh tp/wp-cli.sh conf/nginx.sh conf/php.sh conf/crontab.sh
         local/tdm.sh)

for SCRIPT in ${SCRIPTS[@]}; do
    ~/${repo}/${SCRIPT}
done

答案4

使用 GNU 并行:

parallel ::: ~/${repo}/*/*.sh

如果需要串行:

parallel -j1 ::: ~/${repo}/*/*.sh

这将按字母数字顺序运行脚本,因此如果顺序很重要,请重命名目录和文件夹,如下所示:01_apt/01_security.sh用于--dry-run查看将运行的内容。

如果这匹配太多文件(例如其他目录),请直接提及目录。

parallel ::: ~/${repo}/{apt,third-party,conf,local}/*.sh

如果顺序很重要:

parallel -j1 ::: \
  ~/${repo}/{apt/{security,lemp,certbot,misc},third-party/{pma,wp-cli},conf/{nginx,php,crontab},local/tdm}.sh

最后一个有点违背你避免排长队的愿望。

允许空行的垂直版本:

parallel -rj1 ~/${repo}/{} <<_EOF
apt/security.sh
apt/lemp.sh
apt/certbot.sh
apt/misc.sh

third-party/pma.sh
third-party/wp-cli.sh

conf/nginx.sh
conf/php.sh
conf/crontab.sh

local/tdm.sh
_EOF

相关内容