Pretty-print for shell script

20,724

Solution 1

Vim can indent bash scripts. But not reformat them before indenting.
Backup your bash script, open it with vim, type gg=GZZ and indent will be corrected. (Note for the impatient: this overwrites the file, so be sure to do that backup!)

Though, some bugs with << (expecting EOF as first character on a line) e.g.

EDIT: ZZ not ZQ

Solution 2

In bash I do this:

reindent() {
source <(echo "Zibri () {";cat "$1"; echo "}")
declare -f Zibri|head --lines=-1|tail --lines=+3 | sed -e "s/^\s\s\s\s//"
}

this eliminates comments and reindents the script "bash way".

If you have HEREDOCS in your script, they got ruined by the sed in the previous function.

So use:

reindent() {
source <(echo "Zibri () {";cat "$1"; echo "}")
declare -f Zibri|head --lines=-1|tail --lines=+3"
}

But all your script will have a 4 spaces indentation.

Or you can do:

reindent () 
{ 
    rstr=$(mktemp -u "XXXXXXXXXX");
    source <(echo "Zibri () {";cat "$1"|sed -e "s/^\s\s\s\s/$rstr/"; echo "}");
    echo '#!/bin/bash';
    declare -f Zibri | head --lines=-1 | tail --lines=+3 | sed -e "s/^\s\s\s\s//;s/$rstr/    /"
}

which takes care also of heredocs.

Solution 3

bash5+ has a --pretty-print option.. it will remove comments though, including a first-line '#!/bin...'

Solution 4

shfmt works very well.

You can format bash scripts and also check the formatting from pre-commit hooks.

# reformat
shfmt -l -w script.sh
# check if the formatting is OK
shfmt -d script.sh
# works on the whole directory as well
shfmt -l -w .

The only option absent is that it does not reformat according to line length (yet).

Since it is written in go you can just download the binary for most platforms, e.g. for Travis (.travis.yml):

install:
  - curl -LsS -o ~/shfmt https://github.com/mvdan/sh/releases/download/v3.1.2/shfmt_v3.1.2_linux_amd64
  - chmod +x ~/shfmt
script:
  - ~/shfmt -d .

There is also a cross compiled js version on npm and a lot of editor plugins (see related projects)

Share:
20,724

Related videos on Youtube

PeterMmm
Author by

PeterMmm

AC56EF55D788

Updated on July 09, 2022

Comments

  • PeterMmm
    PeterMmm 11 months

    I'm looking for something similiar to indent but for (bash) scripts. Console only, no colorizing, etc.

    Do you know of one ?

  • Brian Chrisman
    Brian Chrisman almost 4 years
    some tr implementations don't like straight urandom... cat /dev/urandom | base64 can substitute well enough.. thanks
  • Stéphane Gourichon
    Stéphane Gourichon over 3 years
    The last one does not work for me, bash complains. Also, empty lines are lost.
  • Zibri
    Zibri over 3 years
    yes empty lines are lost.. but can be modified for that... i didn't need it.
  • Zibri
    Zibri over 3 years
    you can do another tr "\n\n" "ZZ" before and after tr "ZZ" "\n\n" (but there are a million ways)
  • Zibri
    Zibri over 3 years
    @BrianChrisman or you can just type a static random string... it just must not be present in the code... I used a random one so reindent can reindent itself :D
  • Andrew Beals
    Andrew Beals over 2 years
    Backing up with cp -p $script{,.$(date -Is)} leaves one with a file that one can diff -cw against, showing that this solution works well against a reasonably-complex shell script I tested it against. (no << here text, though)