shfmt(1)

πŸ’… shfmt(1) β€” General Commands Manual, but make it cute

okay so bestie, welcome to the shfmt(1) page from the General Commands Manual β€” this is literally the glow-up station for your shell scripts and i'm obsessed πŸ’–


✨ NAME ✨

shfmt β€” Format shell programs πŸŽ€

✨ SYNOPSIS ✨

shfmt [flags] [path...]

✨ DESCRIPTION ✨

shfmt formats shell programs, periodt. 🫢 If the only argument is a dash (-) or you give it no arguments at all, standard input gets used. And if a given path is a directory, it takes all the shell scripts found under that directory. slay.

If any EditorConfig files are found, they will be used to apply formatting options. But heads up: if any parser or printer flags are given to the tool, then no EditorConfig formatting options will be used β€” like, none, zero, the flags win πŸ’…. You can use a default like -i=0 for this purpose if you just want to shut EditorConfig out.

shfmt's default shell formatting was chosen to be consistent, common, and predictable. Some aspects of the format can be configured via printer flags. it's giving thoughtful πŸ’–


✨ OPTIONS ✨

πŸ¦‹ Generic flags

  • --version β€” Show version and exit. bye bestie πŸ‘‹
  • -l[=0], --list[=0] β€” Error with a list of files whose formatting differs from shfmt; paths are separated by a newline or a null character if -l=0.
  • -w, --write β€” Write result to file instead of stdout. the real glow-up applied directly to your files πŸ’…
  • -d, --diff β€” Error with a diff when the formatting differs.

The diff uses color when the output is a terminal. To never use color, set a non-empty NO_COLOR or TERM=dumb. To always use color, set a non-empty FORCE_COLOR.

  • --apply-ignore β€” Always apply EditorConfig ignore rules.

When formatting files directly, ignore rules are skipped without this flag. Should be useful to any tools or editors which format stdin or a single file. When printing results to stdout, an ignored file results in no output at all. not even a crumb 😭

  • --detect <str> β€” How to detect shell files when walking directories or via --find: default, exec, or all.

By default, files with a non-shell extension like foo.go are skipped; only shell extensions like foo.sh and extensionless files with a shell shebang are used. exec also reads the shebangs of executable files, costing an extra stat per skipped file, and all reads the shebangs of all regular files. ngl that all option is doing the most πŸ”₯

  • --filename str β€” Provide a name for the standard input file.

Use of this flag is necessary for EditorConfig support to work with stdin, since EditorConfig files are found relative to the location of a script. so if stdin's acting mysterious, this is why πŸ‘‘

🌸 Parser flags

  • -ln, --language-dialect <str> β€” Language dialect (bash/posix/mksh/bats/zsh, default auto).

When set to auto, the language is detected from the input filename, as long as it has a shell extension like foo.mksh. Otherwise, if the input begins with a shell shebang like #!/bin/sh, that's used instead. If neither come up with a result, bash is used as a fallback. a queen always has a backup plan πŸ’…

The filename extension .sh is a special case: it implies posix, but may be overridden by a valid shell shebang. iconique ✨

  • -p, --posix β€” Shorthand for -ln=posix.
  • -s, --simplify β€” Simplify the code. less chaos, more slay.

πŸŽ€ Printer flags

  • -i, --indent <uint> β€” Indent: 0 for tabs (default), >0 for number of spaces. tabs girlies rise 🌈
  • -bn, --binary-next-line β€” Binary ops like && and | may start a line.
  • -ci, --case-indent β€” Switch cases will be indented.
  • -sr, --space-redirects β€” Redirect operators will be followed by a space.
  • -kp, --keep-padding β€” Keep column alignment paddings.
🚨 This flag is DEPRECATED and will be removed in the next major version. For more information, see: https://github.com/mvdan/sh/issues/658 β€” like, enjoy it while it lasts bestie 😭
  • -fn, --func-next-line β€” Function opening braces are placed on a separate line.
  • -mn, --minify β€” Minify the code to reduce its size (implies -s). shrinking your script like it's a crop top πŸ’€

🧚 Utility flags

  • -f[=0], --find[=0] β€” Recursively find all shell files and print the paths; paths are separated by a newline or a null character if -f=0.
  • --to-json β€” Print syntax tree to stdout as a typed JSON.
  • --from-json β€” Read syntax tree from stdin as a typed JSON. the round trip is real πŸ”

✨ EXAMPLES ✨

Format all the scripts under the current directory, printing which are modified:

shfmt -l -w .

For CI, one can use a variant where formatting changes are just shown as diffs:

shfmt -d .

The following formatting flags closely resemble Google's shell style defined in https://google.github.io/styleguide/shellguide.html:

shfmt -i 2 -ci -bn

Below is a sample EditorConfig file as defined by https://editorconfig.org/, showing how to set supported options:

[*.sh]
# like -i=4
indent_style = space
indent_size = 4

# --language-dialect
shell_variant      = posix
simplify           = true
binary_next_line   = true
# --case-indent
switch_case_indent = true
space_redirects    = true
keep_padding       = true
# --func-next-line
function_next_line = true
minify             = true

# Ignore the entire "third_party" directory when calling shfmt on directories,
# such as "shfmt -l -w .". When formatting files directly,
# like "shfmt -w third_party/foo.sh" or "shfmt --filename=third_party/foo.sh",
# the ignore logic is applied only when the --apply-ignore flag is given.
[third_party/**]
ignore = true

EditorConfig sections may also use [[shell]], [[bash]], or [[zsh]] to match shell scripts, which is particularly useful when scripts use a shebang but no extension. Note that this feature is outside of the EditorConfig spec and may be changed in the future. so don't get too attached, k? πŸ™ˆ

shfmt can also replace bash -n to check shell scripts for syntax errors. It is more exhaustive, as it parses all syntax statically and requires valid UTF-8:

$ echo '${foo:1 2}' | bash -n
$ echo '${foo:1 2}' | shfmt >/dev/null
1:9: not a valid arithmetic operator: 2
$ echo 'foo=(1 2)' | bash --posix -n
$ echo 'foo=(1 2)' | shfmt -p >/dev/null
1:5: arrays are a bash feature

see how it caught stuff bash just let slide?? main character energy πŸ‘‘


✨ AUTHORS ✨

Maintained by Daniel Martí <mvdan@mvdan.cc>, who is assisted by other open source contributors. For more information and development, see https://github.com/mvdan/sh. 🫢


and that's the whole page, bestie πŸ’– This little gem is shfmt(1) from the General Commands Manual, dated 2026-09-07 β€” go forth and format, you gorgeous shell gremlin βœ¨πŸŽ€πŸ¦‹

πŸ“¦ where this page comes from