name: "IFS" cases: - name: "Default IFS value" stdin: | # Default IFS is space, tab, newline [[ "$IFS" == $' \t\n' ]] && echo "IFS has default value" - name: "Field splitting with default IFS" stdin: | var="one two three four" echo "Fields:" $var - name: "Field splitting with custom single-char IFS" stdin: | IFS=':' var="one:two:three" echo $var - name: "Field splitting with multi-char IFS" stdin: | IFS=':,' var="one:two,three:four" echo $var - name: "Empty IFS disables field splitting" stdin: | IFS='' var="one two three" echo "[$var]" # Should print with all whitespace preserved - name: "Empty IFS with expansion" stdin: | IFS='' var="a b c" set -- $var echo "Count: $#" echo "[$1]" - name: "Unset IFS uses default splitting" stdin: | unset IFS var="one two three" echo $var - name: "IFS whitespace vs non-whitespace splitting" known_failure: true stdin: | # Non-whitespace IFS chars create empty fields IFS=':' var=":one::two:" set -- $var echo "Count: $#" echo "Args: $@" - name: "IFS whitespace splitting ignores leading/trailing" stdin: | # Whitespace IFS chars ignore leading/trailing IFS=' ' var=" one two " set -- $var echo "Count: $#" echo "Args: $@" - name: "Mixed whitespace and non-whitespace IFS" stdin: | IFS=' :' var="one:two three : four" set -- $var echo "Count: $#" for arg in "$@"; do echo "[$arg]" done - name: "Mixed IFS leading non-whitespace" known_failure: true stdin: | IFS=': ' var=":one: :two" set -- $var echo "Count: $#" for arg in "$@"; do echo "[$arg]" done - name: "Mixed IFS trailing non-whitespace" stdin: | IFS=' :' var="one :two: " set -- $var echo "Count: $#" for arg in "$@"; do echo "[$arg]" done - name: "IFS only whitespace multiple chars" stdin: | IFS=$' \t' var=" one two three " set -- $var echo "Count: $#" echo "Args: $@" - name: "IFS only non-whitespace multiple chars" known_failure: true stdin: | IFS=':,' var=":,one,:,two,:" set -- $var echo "Count: $#" for arg in "$@"; do echo "[$arg]" done - name: "IFS only tab character" stdin: | IFS=$'\t' var=" a b " set -- $var echo "Count: $#" echo "Args: $@" - name: "IFS only newline character" stdin: | IFS=$'\n' var=" a b " set -- $var echo "Count: $#" echo "Args: $@" - name: "IFS affects command substitution" stdin: | IFS=':' result=$(echo "a:b:c") # Command substitution itself doesn't split, but expansion does set -- $result echo "$#" echo "$@" - name: "IFS with command substitution multiline" stdin: | IFS=$'\n' result=$(printf "a\nb\nc") set -- $result echo "Count: $#" echo "$1|$2|$3" - name: "IFS affects arithmetic expansion" stdin: | IFS=' ' # Arithmetic expansion result is splittable set -- $((1 + 1)) $((2 + 2)) echo "Count: $#" echo "$@" - name: "IFS in array expansion" stdin: | arr=(one two three) IFS=':' echo "${arr[*]}" # With $* should join with first char of IFS - name: "IFS with $* vs $@" stdin: | set -- one two three IFS=':' echo "$*" echo "$@" - name: "IFS with $* unquoted" stdin: | set -- "a:b" "c:d" IFS=':' # Unquoted $* joins then splits set -- $* echo "Count: $#" for arg in "$@"; do echo "[$arg]" done - name: "IFS null char handling" stdin: | IFS=':' var="" set -- $var echo "Empty var count: $#" - name: "IFS preservation across commands" stdin: | IFS=':' echo "First: $IFS" var="a:b" echo $var echo "After: $IFS" - name: "IFS in subshell" stdin: | IFS=':' ( echo "In subshell: [$IFS]" var="a:b:c" set -- $var echo "Count: $#" ) echo "Parent: [$IFS]" - name: "IFS local to command" stdin: | var="a:b:c" IFS=':' echo $var # IFS assignment should only affect that command echo "After: [$IFS]" - name: "IFS does not affect for loop literal words" # hydrashell: fixed by ExpansionPiece::LiteralText (literal words are not field-split) stdin: | IFS=':' for word in a:b:c; do echo "[$word]" done - name: "IFS affects for loop variable expansion" stdin: | IFS=':' var="a:b:c" for word in $var; do echo "[$word]" done - name: "IFS affects for loop command substitution" stdin: | IFS=':' for word in $(echo "x:y:z"); do echo "[$word]" done - name: "IFS with quoted vs unquoted expansion" stdin: | IFS=':' var="a:b:c" echo "Unquoted:" $var echo "Quoted: $var" - name: "IFS with partially quoted expansion" # hydrashell: fixed by ExpansionPiece::LiteralText (literal words are not field-split) stdin: | IFS=':' var="a:b:c" set -- "$var":more echo "Count: $#" echo "$@" - name: "IFS whitespace sequence handling" stdin: | IFS=' ' var="a b" set -- $var echo "Count: $#" echo "Args: $@" - name: "IFS non-whitespace sequence handling" known_failure: true stdin: | IFS=':' var="a::::b" set -- $var echo "Count: $#" for arg in "$@"; do echo "[$arg]" done - name: "IFS with parameter expansion" stdin: | IFS=':' var="a:b:c" result=${var} set -- $result echo "$#" echo "$@" - name: "IFS with parameter expansion default value" stdin: | IFS=':' set -- ${unset:-a:b:c} echo "Count: $#" echo "$@" - name: "IFS with parameter expansion empty default" stdin: | IFS=':' set -- ${unset:-} echo "Count: $#" - name: "IFS with parameter length" stdin: | IFS=':' var="a:b:c" # Length expansion returns a number, not subject to further splitting len=${#var} set -- $len echo "Count: $#" echo "[$1]" - name: "IFS with glob pattern literal" # hydrashell: fixed by ExpansionPiece::LiteralText (literal words are not field-split) stdin: | IFS=':' # Glob patterns as literals shouldn't split for word in *.txt:*.sh; do echo "[$word]" done - name: "IFS newline handling" stdin: | IFS=$'\n' var="a b c" set -- $var echo "Count: $#" echo "$1|$2|$3" - name: "IFS tab handling" stdin: | IFS=$'\t' var="a b c" set -- $var echo "Count: $#" echo "$1|$2|$3" - name: "IFS with backslash in value" stdin: | IFS=':' var='a\:b:c\:d' set -- $var echo "Count: $#" for arg in "$@"; do echo "[$arg]" done - name: "IFS first char for joining" stdin: | set -- a b c IFS=':' # First char of IFS used for $* joining result="$*" echo "[$result]" - name: "IFS first char empty IFS" known_failure: true stdin: | set -- a b c IFS='' result="$*" echo "[$result]" - name: "IFS multiple whitespace at start" stdin: | IFS=' ' var=" a b" set -- $var echo "Count: $#" echo "$@" - name: "IFS multiple whitespace at end" stdin: | IFS=' ' var="a b " set -- $var echo "Count: $#" echo "$@" - name: "IFS with read builtin integration" stdin: | IFS=':' echo "a:b:c" | (read x y z; echo "x=[$x] y=[$y] z=[$z]") - name: "IFS whitespace before non-whitespace" known_failure: true stdin: | IFS=' :' var=" :a" set -- $var echo "Count: $#" for arg in "$@"; do echo "[$arg]" done - name: "IFS non-whitespace before whitespace" known_failure: true stdin: | IFS=': ' var=": a" set -- $var echo "Count: $#" for arg in "$@"; do echo "[$arg]" done