this post was submitted on 19 Mar 2024
96 points (94.4% liked)

Linux

48017 readers
865 users here now

From Wikipedia, the free encyclopedia

Linux is a family of open source Unix-like operating systems based on the Linux kernel, an operating system kernel first released on September 17, 1991 by Linus Torvalds. Linux is typically packaged in a Linux distribution (or distro for short).

Distributions include the Linux kernel and supporting system software and libraries, many of which are provided by the GNU Project. Many Linux distributions use the word "Linux" in their name, but the Free Software Foundation uses the name GNU/Linux to emphasize the importance of GNU software, causing some controversy.

Rules

Related Communities

Community icon by Alpár-Etele Méder, licensed under CC BY 3.0

founded 5 years ago
MODERATORS
 

What do you advice for shell usage?

  • Do you use bash? If not, which one do you use? zsh, fish? Why do you do it?
  • Do you write #!/bin/bash or #!/bin/sh? Do you write fish exclusive scripts?
  • Do you have two folders, one for proven commands and one for experimental?
  • Do you publish/ share those commands?
  • Do you sync the folder between your server and your workstation?
  • What should've people told you what to do/ use?
  • good practice?
  • general advice?
  • is it bad practice to create a handful of commands like podup and poddown that replace podman compose up -d and podman compose down or podlog as podman logs -f --tail 20 $1 or podenter for podman exec -it "$1" /bin/sh?

Background

I started bookmarking every somewhat useful website. Whenever I search for something for a second time, it'll popup as the first search result. I often search for the same linux commands as well. When I moved to atomic Fedora, I had to search for rpm-ostree (POV: it was a horrible command for me, as a new user, to remember) or sudo ostree admin pin 0. Usually, I bookmark the website and can get back to it. One day, I started putting everything into a .bashrc file. Sooner rather than later I discovered that I could simply add ~/bin to my $PATH variable and put many useful scripts or commands into it.

For the most part I simply used bash. I knew that you could somehow extend it but I never did. Recently, I switched to fish because it has tab completion. It is awesome and I should've had completion years ago. This is a game changer for me.

I hated that bash would write the whole path and I was annoyed by it. I added PS1="$ " to my ~/.bashrc file. When I need to know the path, I simply type pwd. Recently, I found starship which has themes and adds another line just for the path. It colorizes the output and highlights whenever I'm in a toolbox/distrobox. It is awesome.

you are viewing a single comment's thread
view the rest of the comments
[–] [email protected] 10 points 7 months ago* (last edited 7 months ago) (1 children)

I use bash for scripts almost exclusively even though i use zsh interactively (startup scripts for zsh are an obvious exception).

The vast majority of my scripts start with

  set -e -u

which makes the script exit if a command (that is not in a few special places like an if) exits with an error status code and also complains about unbound variables when you use them.

Use

bash -n

and

shellcheck

to test your script for errors and problems if you try it.

Always use curly braces for variables to avoid issues with strings after the variable name being interpreted as part of the variable name.

Always use 10# before numbers in $(()) expressions to avoid leading zeroes turning your decimal number variables into octal ones.

Always use

while read -r foo
do
...
done < <(command ...)

instead of

command ... | while read -r foo
do
...
done

to avoid creating a subshell where some changes you make will not affect your script outside the loop.

In

while read -r foo
do
...
done < ...

loops always make sure you redirect all stdin from /dev/null or otherwise close it with suitable parameters or the content of your loop will eat some of the lines you meant for the read. Alternatively fill a bash array in the loop and then use a for loop to call your commands and do more complex logic.

When using temporary directories or similar resources use

cleanup()
{
 ...
}
trap cleanup EXIT

handlers to clean up after the script in case it dies or is killed (by SIGTERM or SIGINT,...; obviously not SIGKILL).

When writing scripts for cronjobs take into account that the environment (PATH In particular) might be more limited. Also take into account that stderr output and non-zero exit status can lead to an email about the cronjob.

Use pushd and popd instead of cd (especially cd ..), redirect their output to /dev/null. This will prevent your scripts from accidentally running later parts of the script in a wrong directory.

There are probably many other things to consider but that is just standard stuff off the top of my head.

If you do need any sort of data structure and in particular arrays of data structures use a proper programming language. I would recommend Rust since a compiled language is much easier to run on a variety of systems than the Python so many others here recommend, especially if you need to support the oldest supported version of an OS and the newest one at the same time.

[–] [email protected] 3 points 7 months ago (1 children)

Great list! I would add "always surround variables with quotes in case the value contains spaces".

[–] [email protected] 2 points 7 months ago (1 children)

Good point, forgot one of the basics.

Also, to make your scripts more readable and less error prone use something like

if [[ $# -gt 0 ]] && [[ "$1" == "--dry-run" ]]; then
  dry_run=1
  shift
else
  dry_run=0
fi

if [[ $# != 3 ]]; then
  echo "Usage: $0 [ --dry-run ] <description of foo> <description of bar> <description of baz>" >&2
  exit 1
fi

foo="$1"
shift
bar="$1"
shift
baz="$1"
shift

at the start of your script to name your parameters and provide usage information if the parameters did not match what you expected. The shift and use of $1 at the bottom allows for easy addition and removal of parameters anywhere without renumbering the variables.

Obviously this is only for the 90% of scripts that do not have overly complex parameter needs. For those you probably want to use something like getopt or another language with libraries like the excellent clap crate in Rust.

[–] [email protected] 2 points 7 months ago* (last edited 7 months ago)

Thank you very much!