2017-07-31 02:00:50 +02:00
|
|
|
# sh
|
|
|
|
|
2017-09-02 16:19:00 +02:00
|
|
|
[![GoDoc](https://godoc.org/mvdan.cc/sh?status.svg)](https://godoc.org/mvdan.cc/sh)
|
2018-01-03 19:12:40 +02:00
|
|
|
[![Linux & OSX build](https://travis-ci.org/mvdan/sh.svg?branch=master)](https://travis-ci.org/mvdan/sh)
|
|
|
|
[![Windows build](https://ci.appveyor.com/api/projects/status/rxxs08v65aj2fqof?svg=true)](https://ci.appveyor.com/project/mvdan/sh)
|
2017-07-31 02:00:50 +02:00
|
|
|
[![Coverage Status](https://coveralls.io/repos/github/mvdan/sh/badge.svg?branch=master)](https://coveralls.io/github/mvdan/sh)
|
|
|
|
|
|
|
|
A shell parser, formatter and interpreter. Supports [POSIX Shell],
|
2017-09-02 16:19:00 +02:00
|
|
|
[Bash] and [mksh]. Requires Go 1.8 or later.
|
|
|
|
|
2017-07-31 02:00:50 +02:00
|
|
|
### shfmt
|
|
|
|
|
2017-09-02 16:19:00 +02:00
|
|
|
go get -u mvdan.cc/sh/cmd/shfmt
|
2017-07-31 02:00:50 +02:00
|
|
|
|
|
|
|
`shfmt` formats shell programs. It can use tabs or any number of spaces
|
|
|
|
to indent. See [canonical.sh](syntax/canonical.sh) for a quick look at
|
2017-09-02 16:19:00 +02:00
|
|
|
its default style.
|
2017-07-31 02:00:50 +02:00
|
|
|
|
|
|
|
You can feed it standard input, any number of files or any number of
|
|
|
|
directories to recurse into. When recursing, it will operate on `.sh`
|
|
|
|
and `.bash` files and ignore files starting with a period. It will also
|
|
|
|
operate on files with no extension and a shell shebang.
|
|
|
|
|
|
|
|
shfmt -l -w script.sh
|
|
|
|
|
2017-09-02 16:19:00 +02:00
|
|
|
Use `-i N` to indent with a number of spaces instead of tabs. There are
|
|
|
|
other formatting options - see `shfmt -h`.
|
2017-07-31 02:00:50 +02:00
|
|
|
|
2017-11-02 14:41:46 +02:00
|
|
|
Packages are available for [Arch], [CRUX], [Homebrew], [NixOS] and [Void].
|
2017-07-31 02:00:50 +02:00
|
|
|
|
|
|
|
#### Advantages over `bash -n`
|
|
|
|
|
|
|
|
`bash -n` can be useful to check for syntax errors in shell scripts.
|
|
|
|
However, `shfmt >/dev/null` can do a better job as it checks for invalid
|
|
|
|
UTF-8 and does all parsing statically, including checking POSIX Shell
|
|
|
|
validity:
|
|
|
|
|
|
|
|
```
|
|
|
|
$ echo '${foo:1 2}' | bash -n
|
|
|
|
$ echo '${foo:1 2}' | shfmt
|
|
|
|
1:9: not a valid arithmetic operator: 2
|
|
|
|
$ echo 'foo=(1 2)' | bash --posix -n
|
|
|
|
$ echo 'foo=(1 2)' | shfmt -p
|
|
|
|
1:5: arrays are a bash feature
|
|
|
|
```
|
|
|
|
|
|
|
|
### gosh
|
|
|
|
|
2017-09-02 16:19:00 +02:00
|
|
|
go get -u mvdan.cc/sh/cmd/gosh
|
2017-07-31 02:00:50 +02:00
|
|
|
|
2017-09-07 19:02:52 +02:00
|
|
|
Experimental shell that uses `interp`. Work in progress, so don't expect
|
|
|
|
stability just yet.
|
2017-07-31 02:00:50 +02:00
|
|
|
|
|
|
|
### Fuzzing
|
|
|
|
|
|
|
|
This project makes use of [go-fuzz] to find crashes and hangs in both
|
|
|
|
the parser and the printer. To get started, run:
|
|
|
|
|
|
|
|
git checkout fuzz
|
|
|
|
./fuzz
|
|
|
|
|
|
|
|
### Caveats
|
|
|
|
|
|
|
|
* Bash index expressions must be an arithmetic expression or a quoted
|
|
|
|
string. This is because the static parser can't know whether the array
|
|
|
|
is an associative array (string keys) since that depends on having
|
|
|
|
called or not `declare -A`.
|
|
|
|
|
|
|
|
```
|
|
|
|
$ echo '${array[spaced string]}' | shfmt
|
|
|
|
1:16: not a valid arithmetic operator: string
|
|
|
|
```
|
|
|
|
|
|
|
|
* `$((` and `((` ambiguity is not suported. Backtracking would greatly
|
|
|
|
complicate the parser and make stream support - `io.Reader` -
|
|
|
|
impossible. In practice, the POSIX spec recommends to [space the
|
|
|
|
operands][posix-ambiguity] if `$( (` is meant.
|
|
|
|
|
|
|
|
```
|
|
|
|
$ echo '$((foo); (bar))' | shfmt
|
|
|
|
1:1: reached ) without matching $(( with ))
|
|
|
|
```
|
|
|
|
|
|
|
|
* Some builtins like `export` and `let` are parsed as keywords. This is
|
|
|
|
to let the static parser parse them completely and build their AST
|
|
|
|
better than just a slice of arguments.
|
|
|
|
|
|
|
|
### Related projects
|
|
|
|
|
2017-11-02 14:41:46 +02:00
|
|
|
* [dockerised-shfmt] - A docker image of `shfmt`
|
2017-07-31 02:00:50 +02:00
|
|
|
* [format-shell] - Atom plugin for `shfmt`
|
2017-11-02 14:41:46 +02:00
|
|
|
* [micro] - Editor with a built-in plugin for `shfmt`
|
2017-07-31 02:00:50 +02:00
|
|
|
* [shell-format] - VS Code plugin for `shfmt`
|
|
|
|
* [vim-shfmt] - Vim plugin for `shfmt`
|
|
|
|
|
2017-11-02 14:41:46 +02:00
|
|
|
[arch]: https://aur.archlinux.org/packages/shfmt/
|
2017-07-31 02:00:50 +02:00
|
|
|
[bash]: https://www.gnu.org/software/bash/
|
2017-11-02 14:41:46 +02:00
|
|
|
[crux]: https://github.com/6c37/crux-ports-git/tree/3.3/shfmt
|
|
|
|
[dockerised-shfmt]: https://hub.docker.com/r/jamesmstone/shfmt/
|
2017-09-02 16:19:00 +02:00
|
|
|
[examples]: https://godoc.org/mvdan.cc/sh/syntax#pkg-examples
|
2017-11-02 14:41:46 +02:00
|
|
|
[format-shell]: https://atom.io/packages/format-shell
|
|
|
|
[go-fuzz]: https://github.com/dvyukov/go-fuzz
|
2017-07-31 02:00:50 +02:00
|
|
|
[homebrew]: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/shfmt.rb
|
2017-11-02 14:41:46 +02:00
|
|
|
[micro]: https://micro-editor.github.io/
|
|
|
|
[mksh]: https://www.mirbsd.org/mksh.htm
|
2017-07-31 02:00:50 +02:00
|
|
|
[nixos]: https://github.com/NixOS/nixpkgs/blob/HEAD/pkgs/tools/text/shfmt/default.nix
|
2017-11-02 14:41:46 +02:00
|
|
|
[posix shell]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
|
2017-07-31 02:00:50 +02:00
|
|
|
[posix-ambiguity]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_03
|
|
|
|
[shell-format]: https://marketplace.visualstudio.com/items?itemName=foxundermoon.shell-format
|
|
|
|
[vim-shfmt]: https://github.com/z0mbix/vim-shfmt
|
2017-11-02 14:41:46 +02:00
|
|
|
[void]: https://github.com/voidlinux/void-packages/blob/HEAD/srcpkgs/shfmt/template
|