3

I use Ubuntu 16.04 and I have a localization file, a file that executes many files, that I got after downloading my own GitHub project to my machine.

This file contains a Bash script, and is named localize.sh. I run it in a subsession via ~/${repo}/localize.sh.

The file contains many lines, all with the same basic pattern (see below), to execute all relevant files in sub-session.

This is the actual content of that file:

#!/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

One can notice the repetitive ~/${repo}/ pattern.

It isn't a big problem, but it would still be good to reduce these redundant characters as this file should become larger.

What is the most minimal way possible to achieve a DRY (Don’t Repeat Yourself version of that code?

One single long line isn't something I personally would want to use, in this case.

Edit: By principle, there aren't and there shouldn't be any other files in the listed directories, besides the files listed in localize.sh.


Also, it might be that the name localize.sh, as well as calling the action of the file localization is a bad approach; Please criticize me if you think it's bad, in a side note.

  • 1
    does the order of scripts execution matter? – RomanPerekhrest Feb 12 '18 at 13:55
  • Yes. This is why it was important for me to separate them into "stacks" with the empty lines between. – user9303970 Feb 12 '18 at 14:06
  • Maybe: ~/${repo}/**/*.sh? Edit: you’ll need file globbing enabled. – Stan Strum Feb 12 '18 at 18:38
  • Are the names of the .sh files fixed? – roaima Feb 15 '18 at 0:02
  • @roaima what do you mean by fixed? They're just there, aren't changing and shouldn't be changed. – user9303970 Feb 15 '18 at 8:26
1

Assuming that all scripts are located within the common parent directory ~/${repo} you can put them into an array and loop over it:

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
  • This does have the upside that you have total control over the order of the filenames. You could also use brace expansion to avoid repeating the directory names, though not everyone might find it pretty: apt/{security.sh,lemp.sh,certbot.sh,misc.sh} etc... – ilkkachu Feb 14 '18 at 22:58
  • @ilkkachu - he did ask for minimal. (also you could do apt/{misc,lemp...}.sh to save a few bytes) – DarkHeart Feb 15 '18 at 13:45
  • @DarkHeart, yeah, depends on what they mean with "minimal". Least amount of bytes or least amount of distinct features used... – ilkkachu Feb 15 '18 at 13:56
8

It’s not clear whether you’re running all the scripts in the relevant directories, but if you are, you might find run-parts useful:

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

Note that this will run the scripts in alphanumeric order inside each directory, so if order is significant inside a subdirectory you’ll need to rename them (or number them). You can see what run-parts will do ahead of time by running it with the --test option:

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
+100

Whats about a simple and short 'find ${repo} -exec {} \;'?

My example scripts just echo "foo" or "bar" or "baz":

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

you can even alias' to shorten it:

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

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

Then just run

run_myscripts

Just notices that the files need the execute flag. If they don't have it or you are unsure, you just need to extend the 'find ... -exec' command like this:

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

Edit: Ok, didn't notice that the order should be keep. This will change it a bit and I think a good way is to place the order in a textfile and wrap a "while read line" around an execute line.

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

in ordered_scripts.txt you can define the correct order.

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
  • In a script, a shell function would be more apropriate. – Kusalananda Feb 13 '18 at 12:01
  • It will not keep the order as given by OP: "The order of everything should be as I presented". – Ole Tange Feb 16 '18 at 22:36
0

Based on the Answer by Marc, I assume the shortest solution would be something like this:

$ myPath="$HOME/$repo"; find ${path} -type f -iname "*.sh" -exec {} \;
file_1
file_2
...
  • 1
    find will very likely not give you the files in any particular order. You could rig something with sort, but it'd still give you the alphabetical order. – ilkkachu Feb 14 '18 at 22:56
0

With GNU Parallel:

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

If it needs to be serial:

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

This will run the scripts in alphanumeric order, so if order is significant rename the dirs and folders like this: 01_apt/01_security.sh Use --dry-run to see what would be run.

If this matches too many files (e.g. other dirs), mention the dirs directly.

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

If the order matters:

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

The last goes a little against your wish to avoid a long line.

A vertical version that allows for empty lines:

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
  • Thx! The files themselves should be in one long vertical list, not horizontal one. – user9303970 Feb 15 '18 at 17:30
  • How about the dirs? – Ole Tange Feb 15 '18 at 17:36
  • The order of everything should be as I presented (sorry if it sounds harsh, really no such intention). All I try to save here is typing the paths time and again. – user9303970 Feb 15 '18 at 17:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.