You are not logged in.
I recently started to write some scripts and I wonder whether my approach is correct or not in terms of style and how I do common things like executing command as a string.
For example, the following script uses rsync to create backup of my dotfiles. Clearly I avoided such bashism like brace expansion, with the use of which I could specify my backup files and folders like "--include={.bashrc,.bash_profile..}". Instead I used an array and loop for achieving the same goal. Also as a final command of backup I use eval on a string, so at first I create a string which contains the initial part of command and then in a loop I concatenate command string and finally execute it with eval.
#!/bin/sh
DOTFILES=(.bashrc .bash_profile .gitconfig .xinitrc .config/***)
cmd="rsync -aAX --delete-excluded"
for df in "${DOTFILES[@]}"; do
cmd="${cmd} --include=$df"
done
cmd="${cmd} --exclude='*' /home/assertion9/ /run/media/assertion9/root"
eval $cmd
I would appreciate any critique on behalf of this script or how could I improve it further to make efficient. Also I've searched a lot to find any guidelines on writing posix complaint scripts and couldn't find any, please share some books or links for starters or where I could find some ready examples of posix shell scripts. Thank you.
Last edited by assertion9 (2020-06-29 18:05:55)
Offline
shellcheck.net
There are no such things as arrays in POSIX sh.
Offline
please share some books or links for starters
https://pubs.opengroup.org/onlinepubs/9 … hap02.html
https://www.grymoire.com/Unix/Sh.html
https://github.com/dylanaraps/pure-sh-bible
http://www.etalabs.net/sh_tricks.html
shellcheck.net
That's in the [community] repositories: https://www.archlinux.org/packages/comm … hellcheck/
I also like checkbashisms (lifted from Debian's devscripts package).
EDIT: and for POSIX "arrays" see https://github.com/krebs/array
EDIT2: note that /bin/sh in Arch is linked to bash by default (which is why your array worked) — it can be linked to dash instead, as Debian do: https://wiki.archlinux.org/index.php/Da … ng_/bin/sh
Last edited by Head_on_a_Stick (2020-06-29 18:07:14)
Para todos todo, para nosotros nada
Offline
assertion9 wrote:please share some books or links for starters
https://pubs.opengroup.org/onlinepubs/9 … hap02.html
https://www.grymoire.com/Unix/Sh.html
https://github.com/dylanaraps/pure-sh-bible
http://www.etalabs.net/sh_tricks.htmlScimmia wrote:shellcheck.net
That's in the [community] repositories: https://www.archlinux.org/packages/comm … hellcheck/
I also like checkbashisms (lifted from Debian's devscripts package).
EDIT: and for POSIX "arrays" see https://github.com/krebs/array
I really appreciate it, thank you
Offline
No need for the loop, printf itself will loop through arguments:
DOTFILES='.bashrc .bash_profile .gitconfig .xinitrc .config/***'
cmd="rsync -aAx --delete-excluded"
cmd="$cmd $(printf ' --include=%s' $DOTFILES)"
cmd="$cmd --exclude='*' /home/assertion9/ /run/media/assertion9/root"
Of course I think you could rethink the whole approach. There is a lot to know about good shell scripting, but in my book, the most important thing to understand is the component programs that you are stringing together in the script. Use their built-in efficiencies rather than reinventing the wheel. In this case, use rsync's '--include-from' parameter. I can't check this locally to confirm that it will read from /dev/stdin for this parameter, but I'm pretty sure it would. If not, this could be reworked to use a file descriptor or a temp file:
rsync -aAx --delete-excluded --include-from=/dev/sdin --exclude='*' /home/assertion9/ /run/media/assertion9/root <<'EOF'
.bashrc
.bash_profile
.gitconfig
.xinitrc
.config/***
EOF
On arrays, POSIX shells do have one array. While I don't think it'd be a good use here, you could adjust your original approach to keep using the array and loop:
set -- .bashrc .bash_profile .gitconfig .xinitrc .config/***
cmd="rsync -aAX --delete-excluded"
for df in $@; do
...
And as a side note Thank You for taking an interested in making more portable shell scripts. It's a passion of mine to advocate for broader portability where practical; there are goals for which features of a given shell (e.g., BASH) may really help, but there are lots of scripts that use bashisms for no real benefit, and neglect the portability costs. This is particularly frustrating when the author isn't even aware of this and puts a /bin/sh shebang at the top.
Last edited by Trilby (2020-06-29 18:25:56)
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
No need for the loop, printf itself will loop through arguments:
DOTFILES='.bashrc .bash_profile .gitconfig .xinitrc .config/***' cmd="rsync -aAx --delete-excluded" cmd="$cmd $(printf ' --include=%s' $DOTFILES)" cmd="$cmd --exclude='*' /home/assertion9/ /run/media/assertion9/root"
Of course I think you could rethink the whole approach. There is a lot to know about good shell scripting, but in my book, the most important thing to understand is the component programs that you are stringing together in the script. Use their built-in efficiencies rather than reinventing the wheel. In this case, use rsync's '--include-from' parameter. I can't check this locally to confirm that it will read from /dev/stdin for this parameter, but I'm pretty sure it would. If not, this could be reworked to use a file descriptor or a temp file:
rsync -aAx --delete-excluded --include-from=/dev/sdin --exclude='*' /home/assertion9/ /run/media/assertion9/root <<'EOF' .bashrc .bash_profile .gitconfig .xinitrc .config/*** EOF
On arrays, POSIX shells do have one array. While I don't think it'd be a good use here, you could adjust your original approach to keep using the array and loop:
set -- .bashrc .bash_profile .gitconfig .xinitrc .config/*** cmd="rsync -aAX --delete-excluded" for df in $@; do ...
Got it, all three methods works flawlessly. Completely forgot that I could take advantage of heredoc. Thanks a lot
Offline
Scimmia wrote:shellcheck.net
That's in the [community] repositories: https://www.archlinux.org/packages/comm … hellcheck/
Sure, but have you tried installing it? Or keeping it up to date? Packaging haskell is not really sane.
Offline
Sure, but have you tried installing it? Or keeping it up to date? Packaging haskell is not really sane.
Which is exactly why I dropped it for shellcheck-bin. It was the only haskell package on my system and the daily hundreds of updates never sat well with me.
Offline
Which is exactly why I dropped it for shellcheck-bin. It was the only haskell package on my system and the daily hundreds of updates never sat well with me.
Me either. Thanks for the great tip.
Offline