xref: /spdk/doc/shfmt.md (revision cc6920a4763d4b9a43aa40583c8397d8f14fa100)
1# shfmt {#shfmt}
2
3## In this document {#shfmt_toc}
4
5* @ref shfmt_overview
6* @ref shfmt_usage
7* @ref shfmt_installation
8* @ref shfmt_examples
9
10## Overview {#shfmt_overview}
11
12The majority of tests (and scripts overall) in the SPDK repo are written
13in Bash (with a quite significant emphasis on "Bashism"), thus a style
14formatter, shfmt, was introduced to help keep the .sh code consistent
15across the entire repo. For more details on the tool itself, please see
16[shfmt](https://github.com/mvdan/sh).
17
18We also advise to use 4.4 Bash as a minimum version to make sure scripts
19across the whole repo work as intended.
20
21## Usage {#shfmt_usage}
22
23On the CI pool, the shfmt is run against all the updated .sh files that
24have been committed but not merged yet. Additionally, shfmt will pick
25all .sh present in the staging area when run locally from our pre-commit
26hook (via check_format.sh). In case any style errors are detected, a
27patch with needed changes is going to be generated and either build (CI)
28or the commit will be aborted. Said patch can be then easily applied:
29
30~~~{.sh}
31# Run from the root of the SPDK repo
32patch --merge -p0 <shfmt-3.1.0.patch
33~~~
34
35The name of the patch is derived from the version of shfmt that is
36currently in use (3.1.0 is currently supported).
37
38Please, see ./scripts/check_format.sh for all the arguments the shfmt
39is run with. Additionally, @ref shfmt_examples has more details on how
40each of the arguments behave.
41
42## Installation {#shfmt_installation}
43
44The shfmt can be easily installed via pkgdep.sh:
45
46~~~{.sh}
47./scripts/pkgdep.sh -d
48~~~
49
50This will install all the developers tools, including shfmt, on the
51local system. The precompiled binary will be saved, by default, to
52/opt/shfmt and then linked under /usr/bin. Both paths can be changed
53by setting SHFMT_DIR and SHFMT_DIR_OUT in the environment. Example:
54
55~~~{.sh}
56SHFMT_DIR=/keep_the_binary_here \
57SHFMT_DIR_OUT=/and_link_it_here \
58  ./scripts/pkgdep.sh -d
59~~~
60
61## Examples {#shfmt_examples}
62
63~~~{.sh}
64#######################################
65if foo=$(bar); then
66  echo "$foo"
67fi
68
69exec "$foo" \
70  --bar \
71  --foo
72
73# indent_style = tab
74
75if foo=$(bar); then
76        echo "$foo"
77fi
78
79exec foobar \
80        --bar \
81        --foo
82######################################
83if foo=$(bar); then
84        echo "$foo" && \
85        echo "$(bar)"
86fi
87# binary_next_line = true
88if foo=$(bar); then
89        echo "$foo" \
90                && echo "$(bar)"
91fi
92
93# Note that each break line is also being indented:
94
95if [[ -v foo ]] \
96&& [[ -v bar ]] \
97&& [[ -v foobar ]]; then
98	echo "This is foo"
99fi
100# ->
101if [[ -v foo ]] \
102        && [[ -v bar ]] \
103        && [[ -v foobar ]]; then
104        echo "This is foo"
105fi
106
107# Currently, newlines are being escaped even if syntax-wise
108# they are not needed, thus watch for the following:
109if [[ -v foo
110        && -v bar
111        && -v foobar ]]; then
112        echo "This is foo"
113fi
114#->
115if [[ -v foo && -v \
116        bar && -v \
117        foobar ]]; then
118        echo "This is foo"
119fi
120# This, unfortunately, also breaks the -bn behavior.
121# (see https://github.com/mvdan/sh/issues/565) for details.
122######################################
123case "$FOO" in
124        BAR)
125        echo "$FOO" ;;
126esac
127# switch_case_indent = true
128case "$FOO" in
129        BAR)
130                echo "$FOO"
131                ;;
132esac
133######################################
134exec {foo}>bar
135:>foo
136exec {bar}<foo
137# -sr
138exec {foo}> bar
139: > foo
140exec {bar}< foo
141######################################
142# miscellaneous, enforced by shfmt
143(( no_spacing_at_the_beginning & ~and_no_spacing_at_the_end ))
144: $(( no_spacing_at_the_beginning & ~and_no_spacing_at_the_end ))
145
146# ->
147((no_spacing_at_the_beginning & ~and_no_spacing_at_the_end))
148: $((no_spacing_at_the_beginning & ~and_no_spacing_at_the_end))
149~~~
150