I have a large shell script that uses a mixture of spaces and tabs. I want to re-indent the whole file based on syntax, like Eclipse's Format. Is there a program (beautify ?) that will do this ?

I'm having a hard time figuring out the logic with everything jammed together e.g.

   if [ "$CANCELLATION" ]
   while test $num -gt 0
    if [ "$cjb" -gt 0 ]

Learned how to call functions in Vim but that didn't work.

Emacs - lost all the newlines


Emacs can do that:

  • load the file into Emacs
  • press Ctrl-space at the top of the file
  • move the cursor to the bottom of the file
  • press Alt-X and type untabify then return
  • press Alt-X and type indent-region then return

This will get rid of tabs and indent everything properly.

If you need to do this more often and do not use Emacs as your editor, you might want to pack it all into a script:

#!/usr/bin/emacs --script

(setq require-final-newline 'visit)

(defun indent-files (files)
  (cond (files
         (find-file (car files))
         (untabify (point-min) (point-max))
         (indent-region (point-min) (point-max))
         (indent-files (cdr files)))))

(indent-files command-line-args-left)

;; EOF ;;
  • 1
    not really an emacs guy - but if the super shell vim doesn't work. I'll try that. – jsymolon Sep 10 '09 at 14:21
  • 1
    M-> is the usual binding for end-of-buffer. Because taking your hands off the keyboard is evil. – dmckee --- ex-moderator kitten Sep 10 '09 at 21:52
  • 3
    Also marking the entire buffer can be done with C-x h, which runs mark-whole-buffer. – Victor Feb 18 '13 at 16:14
  • Brilliant! Two things: (i) I have to re-select the region after untabify as everything gets unselected, and (2) did this not just use to be in the menu as well? It deserves to be! – alle_meije Jul 26 '18 at 12:15

In Vi/Vim once you've set the correct file syntax (:set syntax=sh), you can press: gg=G (or 1G=G) to correct indentation of the entire file.

Here is the command to format the whole file in-place:

ex +"set syn=sh" +"norm gg=G" -cwq foobar.sh

Note: Make a backup before running above command.

To test the formatting first, edit the file in Vim and run: :norm gg=G.

See also: Re-indenting badly indented code at Vi SE

  • 2
    I just tried this (Vim 8.0) and it didn't work correctly. My guess is that it tried to indent the shell script as if it were C code; it handled curly braces correctly but not if and fi keywords. Perhaps some plugin is required? – Keith Thompson Feb 22 '18 at 22:36
  • Actually, you should be setting filetype=sh (or ft). – lingfish Mar 5 '19 at 6:39
  • This does not work well at all. It makes a mess of my complex Bash script. – Roel Van de Paar Apr 18 '20 at 0:48

It looks like shfmt could do the trick for you. It formats shell/bash code, which includes indentation.

shfmt -l -w script.sh
  • 1
    While this may answer the question, it would be a better answer if you could provide some explanation why it does so. Pehaps you can give an example of how to use it? – DavidPostill Apr 8 '18 at 15:08
  • GREAT! This worked! I used two spaces as ident, so my command was shfmt -i 2 -ci ~/mariadb-qa/pquery-run.sh – Roel Van de Paar Apr 18 '20 at 0:51

You probably want Super Shell Indent. Save it to ~/.vim/indent and when you're next in vim, execute :source ~/.vim/indent/sh.vim

You also probably want to setup file based smart indenting in your .vimrc

" Turn on smart indenting
filetype indent on
set smartindent

If you don't mind vim messing with your formatting, add this line to vimrc too.

" When you load/save a shell script, auto indent it
autocmd BufRead,BufWritePre *.sh normal gg=G

Anyway, here is what you've been waiting for. When you're next editing a shell script in vim, assuming you've turned on smart indenting and installed super shell ident, just hit the follow keys to reindent your script: gg=G

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.