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