General Advice for shell scripts

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.

nawordar,
  • Fish. Much, much saner defaults.
  • I am writing #!/usr/bin/env sh for dead simple scripts, so they will be a tiny bit more portable and run a tiny bit faster. The lack of arrays causes too much pain in longer scripts. I would love to use Fish, but it lacks a strict mode.
  • No, why would I?
  • I used to share all my dotfiles, scripts included, but I was too afraid that I would publish some secrets someday, so I stopped doing that. For synchronizing commands, aliases and other stuff between computers I use Chezmoi.
  • To use Fish instead of fighting with start up time of Zsh with hundreds of plugins
  • Always use the so-called “strict mode” in Bash, that is, the set -euo pipefail line. It will make Bash error on non-zero exit code, undefined variables and non-zero exit codes in commands in pipe. Also, always use shellcheck. It’s extremely easy to make a mistake in Bash. If you want to check the single command exit code manually, just wrap it in set +e and set -e.
  • Consider writing your scripts in Python. Like Bash, it also has some warts, but is multiplatform and easy to read. I have a snippet which contains some boilerplate like a main function definition with ArgumentParser instantiated. Then at the end of the script the main function is called wrapped in try … except KeyboardInterrupt: exit(130) which should be a default behavior.
  • Absolutely not a bad practice. If you need to use them on a remote server and can’t remember what they stand for, you can always execute type some_command. Oh, and read about abbreviations in Fish. It always expands the abbreviation, so you see what you execute.
MigratingtoLemmy,

I use sh to attempt to keep it compatible with POSIX systems.

I use pain bash. Never really tried zsh and fish, since most of my Linux work is on servers and I don’t really care for extra features.

I try and write idempotent scripts when possible.

I wouldn’t create those aliases on a fleet because writing them to the configuration file of your shell in an idempotent fashion is hacky and my VMs are like cattle.

EpicVision,

Do you use bash? If not, which one do you use? zsh, fish? Why do you do it?

Mostly fish, because it just feels much more modern than bash, it has good built-in autocomplete and I don’t have to install millions of plugins like of zsh.

Do you write #!/bin/bash or #!/bin/sh? Do you write fish exclusive scripts?

#!/usr/bin/env bashOccasionally I also write fish scripts. Just replace sh with fish.

What should’ve people told you what to do/ use?

zoxide

general advice?

As @crispy_kilt already suggested, use shellcheck.

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?

I don’t think so

ace_garp,
@ace_garp@lemmy.world avatar

Yes, using bash on all boxen.

Scripts start with #!/bin/sh ,because, that gives quicker execution times.

Any simple aliases, I put in .bash_aliases

Tried tcsh and zsh around 30yrs ago, all bash since then.

Hammerheart,

Do you have to chmod all your scripts when you include the shebang? Or do you have it configured to save with the right permissions?

ace_garp,
@ace_garp@lemmy.world avatar

I chmod 755 each manually. I’ve never tried the automatic way, sounds easier.

TCB13,
@TCB13@lemmy.world avatar

Do you use bash? Yes because it is everywhere and available by default.

danielquinn, (edited )
@danielquinn@lemmy.ca avatar

I recommend writing everything in Bourne shell (/bin/sh) for a few reasons:

  • Bash is more capable, which is nice, but if you’re fiddling with complex data structures, you probably should be using a more maintainable language like Python.
  • Bash is in most places, but crucially not everywhere. Docker-based deployments for example often use Ash which is very similar to Bash, but lacks support for arrays and a few other things.
  • Bourne’s limitations force you to rethink your choices regularly. If you find yourself hacking around a lack of associative arrays for example, it’s probably time to switch to a proper language.

Also two bits of advice.

  1. Use shellcheck. There’s a website that’ll check your script for you as well as a bunch of editor extensions that’ll do it in real time. You will absolutely write better, safer code with it.
  2. If your script exceeds 300 lines. Stop and rewrite it in a proper language. Your future self will thank you.
jbd,

I use fish shell only now. Used to only write bash, but I’ve started writing some fish scripts. I wouldn’t try to plan too much WRT shell scripting up front. Just fix your pain points as you go.

Pantherina,

Yes fish is great. It has some special syntax for functions, I will add my configs soo.

set fish_greeting is useful to silence it.

User scripts can go to ~/.local/bin which is already in the path.

You can split up your shell configs into topics, and put them into ~/.config/fish/conf.d/abc.conf

BrianTheeBiscuiteer,

Bash script for simple things (although Fish is my regular shell) and Node or Python scripts for complex things. Using #!/usr/bin/env node works just like it would for Bash so you know.

lolcatnip,

This. I still write plenty of bash scripts, but I’ve noticed that except for really simple cases, I very quickly reach a point where I would have been better off using Python instead. And when I start with a Python scripts I often end up redoing it in Rust for a variety of reasons. It’s just easy to underestimate how serious a programming project is. At least I’ve never started something in bash that I needed to migrate to Rust.

(I think a lot of people would see Go as the next logical step from Python, but I personally find some things about Go really irritating.)

jherazob,
@jherazob@beehaw.org avatar

A good idea i have been spreading around relevant people lately is to use ShellCheck as you code in Bash, integrate it in your workflow, editor or IDE as relevant to you (there’s a commandline tool as well as being available for editors in various forms), and pass your scripts through it, trying to get the warnings to go away. That should fix many obvious errors and clean up your code a bit.

gnuhaut,

Btw, if you ever wondered why Debian uses dash as /bin/sh (the switch was a bit annoying at the time), I think the reasoning was something like this:

  • dash is a bit faster, which might have saved a second or two on boot times (this was before systemd). Same applies to compilation times, configure scripts run faster with dash.
  • A bunch of #!/bin/sh scripts in Debian did not actually work if you replaced /bin/sh with another shell, which I guess some people wanted to do. Making dash the default /bin/sh forced everyone to fix their scripts.

Also some history on the abomination that is m4sh, famously used by GNU autoconf configure.ac scripts. Apparently when autoconf was released in 1991, there were still some Unix systems that shipped some 70s shells as the default /bin/sh. These shells do not support shell functions, which makes creating any sort of shell programming library pretty much impossible (I guess you could make a folder full of scripts instead of functions). They decided to use m4 preprocessor macros instead, as a sort of poor man’s replacement for functions.

In hindsight, it wish they had told commercial Unix sysadmins to install a proper /bin/sh or gtfo. But the GNU people thought it was important to make it as easy as possible to install free software even on commercial Unices.

Dirk,
@Dirk@lemmy.ml avatar
  • 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?

I use bash, and I use #!/bin/bash for my scripts. Some are POSIX compliant, some have bashisms. But I really don’t care about bashisms, since I explicitly set the bash as interpreter. So no, no fish exclusive scripts, but some “bash exclusive” scripts. Since fish is aimed towards being used as interactive shell I don’t see a real reason to use it as interpreter for scripts anyways.

  • 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?

I have my scripts in $HOME/.scripts and softlink them from a directory in $PATH. Some of the scripts are versioned using Git, but the repository is private and I do not plan sharing them because the repoand the scripts scripts contain some not-tho-share information and mostly are simply not useful outside my carefully crafted and specific environment. If I want to share a script, I do it individually or make a proper public Git repository for it.

Since my server(s) and my workstations have different use cases I do not share any configuration between them. I share some configuration between different workstations, though. My dotfiles repository is mainly there for me to keep track of changes in my dotfiles.

is it bad practice to create a handful of commands

It becomes bad practice if it is against your personal or corporate guidelines regarding best practices. While it is not particularly bad or insecure, etc. to create bash scripts containing a single command, maybe use an alias instead. The $1 is automatically the first parameter after typing the alias in the shell.


<span style="color:#62a35c;">alias </span><span style="font-weight:bold;color:#795da3;">podup</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#183691;">"podman compose up -d"
</span><span style="color:#62a35c;">alias </span><span style="font-weight:bold;color:#795da3;">poddown</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#183691;">"podman compose down"
</span><span style="color:#62a35c;">alias </span><span style="font-weight:bold;color:#795da3;">podlog</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#183691;">"podman logs -f --tail 20"
</span>

Not quite sure about the podman syntax, if podman exec /bin/sh -it “$1” also works, you can use alias podenter="podman exec /bin/sh -it, Otherwise a simple function would do the trick.

Strit,
@Strit@lemmy.linuxuserspace.show avatar

I use bash and I usually put /bin/bash in my scrtipts, because that’s where I know it works. /bin/sh is only if it works on many/all shells.

I don’t have many such scripts, so I just have one. I don’t really share them, as they are made for my usecase. If I do create something that I think will help others, then yes, I share them in git somewhere.

I do have a scripts folder in my Nextcloud that I sync around with useful scripts.

Some of your examples can probably just be made into aliases with alias alias_name=“command_to_run”.

GravitySpoiled,

thx! Why do you think that aliases are better for it?

I moved away from aliases because I have a neat command management where each command is one script.

Strit,
@Strit@lemmy.linuxuserspace.show avatar

I can’t speak for anyone else, but for me, it’s just one file to backup to keep all your custom commands (.bashrc) while it would be many files if you have a script for each.

I can’t see the benefit of having a script for just one command (with arguments) unless those arguments contain variables.

Quackdoc,
@Quackdoc@lemmy.world avatar

I make my scripts with modern shells in mind since they let you use arrays for arguments which is vastly superior to doing `` for continuing the script line, I give the example here docs.blissos.org/…/advanced-qemu-config/

  • All
  • Subscribed
  • Moderated
  • Favorites
  • linux@lemmy.ml
  • fightinggames
  • All magazines