10

I want to catch if a variable is multiline in a case statement in POSIX shell (dash).

I tried this:

q='
'
case "$q" in
    *$'\n'*) echo nl;;
    *) echo NO nl;;
esac

It returns nl in zsh but NO nl in dash.

Thanks.

14

The dash shell does not have C-strings ($'...'). C-strings is an extension to the POSIX standard. You would have to use a literal newline. This is easier (and looks nicer) if you store the newline in a variable:

#!/bin/dash

nl='
'

for string; do

    case $string in
        *"$nl"*)
            printf '"%s" contains newline\n' "$string"
            ;;
        *)
            printf '"%s" does not contain newline\n' "$string"
    esac

done

For each command line argument given to the script, this detects whether it contains a newline or not. The variable used in the case statement ($string) does not need quoting, and the ;; after the last case label is not needed.

Testing (from an interactive zsh shell, which is where the dquote> secondary prompt comes from):

$ dash script.sh "hello world" "hello
dquote> world"
"hello world" does not contain newline
"hello
world" contains newline
3
  • 4
    $nl doesn't need quoting in the case statement, but it would if it contained wildcards. While ;; is optional immediately before esac, omitting it makes maintenance harder because you have to remember to add it if you add another case, so I recommend always including it. Oct 31 '19 at 14:46
  • 3
    @Gilles'SO-stopbeingevil' Yes, the $nl should be quoted (now fixed), but using or not using ;; before esac is clearly a matter of taste.
    – Kusalananda
    Oct 31 '19 at 15:40
  • Another idea for the initializing the $nl constant: nl=$(printf "\nx") && nl=${nl%x}. That makes it a bit more obvious what's actually in $nl (does it include tabs, spaces, etc.?).
    – jrw32982
    Nov 6 '19 at 22:26
2

You can include a literal newline (in quotes) as the pattern, just as you did in assigning to the variable:

q='
'
case "$q" in
    *'
'*) echo nl;;
    *) echo NO nl;;
esac

This makes the formatting ugly (you cannot indent the end quote), but should be fully portable. I tested in bash, zsh, ksh, and dash.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.