Lustre Script Coding Style

Bash Style
local mybool=false        # or true if $mybool; then do_stuff fi       for ((i=0; i < $var; i++)); do                something_with $i done
 * Bash is a programming language. It includes functions.  Shell code outside of functions is effectively code in an implicit main function.  An entire function should be fully seen on one page (~70-90 lines) and be readily comprehensible.  If you have any doubts, then it is too complicated.  Make it easier to understand by separating it into subroutines.
 * The total length of a line (including comment) must not exceed 80 characters. Take advantage of bash's   operator for constants or linefeed escapes.
 * Lines can be split without the need for a linefeed escape after,  ,   and   operators.
 * The indentation must use 8-column tabs and not spaces. For line continuation, an additional tab should be used to indent the continued line, or align after  or   for continued logic operations.
 * Comments are just as important in a shell script as in C code.
 * Use  instead of   for subshell commands:
 * is easier to see the start and end of the subshell command
 * avoids confusion between  and   with a small font
 * can be nested
 * Use the subshell syntax only when you have to:
 * When you need to capture the output of a separate program
 * Using the construct with functions leads to stray output and/or convoluted code struggling to avoid output pollution
 * It is more computationally efficient to not fork the Bash process. Bash is slow enough already.
 * Use "here string" like  instead of   to avoid forking a subshell and pipe
 * Use file arguments like  or input redirection like   instead of a useless use of
 * Use built-in Bash Parameter Expansion for variable/string manipulation rather than forking :
 * Use  or   to remove   or   respectively
 * Use  to replace   with string
 * Avoid use of " " since " works just as well and avoids a separate fork + pipe
 * If a variable is intended to be used as a boolean, then it must be assigned as follows:
 * for loops it is possible to avoid a subshell for  using the built-in iterator for fixed-length loops:
 * Unfortunately,  does not work, so use   arithmetic operator
 * Use  instead of   for clarity and simplicity
 * Use  instead of
 * The  test understands regular expression matching with the   operator
 * The easiest way to use it is by putting the expression in a variable and expanding it after the operator without quotes.
 * Use  instead of   or   when evaluating numerical expressions
 * This can include mathematical operators like
 * This uses normal,  ,   comparisons instead of  ,  ,
 * Use  for arithmetic expressions instead of
 * No need for  when referencing variable names inside
 * can handle hex values and common math operators
 * Error checks should prefer the form  to avoid leaving a dangling "false" on the return stack
 * Otherwise,  will leave a dangling "false" on the stack if   fails and an immediately following return/end of function will return an error

Variables
local start=$SECONDS do something local elapsed=$((SECONDS - start))
 * Names of variables local to current test function which are not exported to the environment should be declared with " " and use lowercase letters
 * Names of global variables or variables that exported to the environment should be UPPERCASE letters
 * Use  for temporary non-Lustre files instead of
 * Wse  to get the current time when measuring test durations instead of   fork+exec:

Functions
local facet=$1 local file="$2" local size=$3
 * Each function must have a section describing what it does and explain the list of parameters
 * 1) One line description of this function's purpose
 * 2) More detailed description of what the function is doing if necessary
 * 3) usage: function_name [--option argument] {required_argument} ...
 * 4) option: meaning of "option" and its argument
 * 5) required_argument: meaning of "required_argument"
 * 6) expected output and/or return value(s)
 * 1) required_argument: meaning of "required_argument"
 * 2) expected output and/or return value(s)
 * 1) expected output and/or return value(s)
 * Function arguments should be given local variable names for clarity, rather than being used as  in the function
 * Use  instead of , since   is RHEL-specific

Tests and Libraries

 * To avoid clustering a single  file, there should be a   file for each test that contains specific functions and variables for that test.
 * Any functions, variables that global to all tests should be put in
 * A test file only need to source  and necessary   file

Subtests
stack_trap "rm -f $DIR/$tfile.big" fallocate -l 100M $DIR/$tfile.big || error "$tfile.big create failed" stack_trap "unlinkmany $DIR/$tdir/$tfile- 1000" createmany -o $DIR/$tdif/$tfile- 1000 || error "$tfile creation failed" lfs migrate -c3 $tfile || error "'lfs migrate -c3' failed" lfs migrate -c1 $tfile || error "second 'lfs migrate -c1' failed" (( MDS1_VERSION_CODE >= $(version_code 2.15.53) )) || skip "need MDS >= 2.15.53 to check foobar works" $mds1_FSTYPE == "ldiskfs" || skip "MDS is not ldiskfs" kinit || skip_env "Kerberos not installed"
 * test files should be named  for the filename, or base name like   or   to simplify debugging
 * test directories should be named, and should be used if a large number of files are created for the subtest
 * small/few test files/dirs do not need to be explicitly deleted at the end of the test, that is done by test-framework.sh at the start/end of each test script
 * large (over 1MB)/many (over 50) test files/dirs in a subtest should be cleaned up explicitly with a  so that they are always cleaned up even if the test exits with an error, and do not fill the test filesystem
 * creating large test files is by far the fastest with "fallocate" *when supported* (ldiskfs only), as determined by
 * use  to add some variety to directory creation (random local, striped, remote) if directory location is not critical to the test
 * ensure that directory location and MDS facet are aligned. Since 2.14.54 directories may be created on any MDT, so " " may be on the wrong MDS.
 * Use " " to create directories on MDT0000 for use with, or " " to determine MDT index, and " " for facet name.
 * the  messages in a subtest should be unique so that it is easy to determine which check failed
 * use  to skip subtests that should not run because of permanent functional deficiency (e.g. non-existent functionality in backing filesystem, older version of client/server, wrong configuration)
 * use  for minor environmental deficiency in developer test environment (e.g. missing binary) that _should_ exist in autotest: