Check if a shell variable has more than one line using built-ins?
Solution 1
The POSIX way:
NL='
'
case $myvar in
*"$NL"*) echo more than one line ;;
*) echo one line ;;
esac
This also works in pre-POSIX Bourne-like shells, too.
Solution 2
The following snippets works in bash
(with and without the -posix
option):
#!/bin/bash
#!/bin/bash -posix
version_1 () { [[ "$myvar" = *$'\n'* ]]; }
version_2 () {
local newlines="${myvar//[^$'\n']/}"
[[ "${#newlines}" -eq 1 ]]
}
for test in version_1 version_2; do
if $test; then echo many lines; else echo one line; fi
done
Solution 3
Here is a way that should work with all Bourne syntax / POSIX shells and uses only builtins :
if (set -f ; IFS=$'\n'; set -- x${myvar}x ; [ $# = 1 ]) ; then
echo "Your variable has only one line, proceeding"
else
echo "Error condition, variable must have exactly one line"
fi
If your shell doesn't support IFS=$'\n'
(like dash
0.5.7), you can use instead :
IFS="
"
Solution 4
I'd recommend using Bash parameter expansion as follows:
n="${myvar//[^\n]}"; if [ ${#n} -eq 1 ]; then
echo "Your variable has only one line, proceeding"
else
echo "Error condition, variable must have only one line"
fi
Test Samples:
myvar="xxx"
myvar="xx\nxx"
myvar="xx\nx\nx"
Related videos on Youtube
![Wildcard](https://i.stack.imgur.com/SbCyV.png?s=256&g=1)
Wildcard
Updated on September 18, 2022Comments
-
Wildcard almost 2 years
I can do this by calling the external utility
sed
(for a known non-empty$myvar
) like so:if [ "$(printf %s "$myvar" | sed -n '$=')" -eq 1 ]; then echo "Your variable has only one line, proceeding" else echo "Error condition, variable must have only one line" fi
Is there a way to do this using only
bash
builtins?Even better, is there a way to do this in a POSIX-specified manner, without calling external utilities?
(This question is one of curiosity and finding better ways to do things; the above code does function. I'm wondering if there is a cleaner/faster way.)
-
Admin about 8 yearsWith that function, the result of
myvar="ab"
is exactly the same as the result ofmyvar=$'ab\n'
. Should a trailing newline be ignored?. In my opinion, it shouldn't. -
Admin about 8 years@BinaryZebra, you are absolutely correct for the general case. In my specific case, I was setting the variable in the first place using command substitution, so was guaranteed to have no trailing newlines.
-
Admin about 8 yearsSo, if the variable has no trailing "new line" and contains no "new line" it should be counted as "one line". If a trailing "new line" is added, it should be counted as "one more", correct?. There is only one case left that the function with sed fails to process and in my opinion should be counted as "one line" (there are no "new lines" included in the variable). ... ... ... what if
myvar=''
orunset myvar
? -
Admin about 8 years@BinaryZebra, this is what I get for failing to assiduously reduce my code to a simplest case standalone example. :) The conditional line itself is taken from my actual production script; the
echo
lines are obviously filler. Earlier in the script (just after the command substitution) I checked that the variable started with the expected pattern—so I already know the variable is not empty or unset. This is my question post, not an answer, so I don't feel it's necessary to edit it at this point, but feel free to propose one if you see a simple way to make it clearer.
-
-
Lucas about 8 yearsI think this you need to set
IFS
otherwise the answer is wrong:sh -c 'a="x y"; set -- $a; echo $#'
prints2
for me,sh -c $'a="x y"; IFS="\n"; set -- $a; echo $#'
on the other hand prints1
. -
jlliagre about 8 years@Lucas Thanks for your comment, answer updated.
-
Stéphane Chazelas about 8 yearsThe
set -f
will apply to future commands. You needset -f
; set -- $myvar. Also
set -- $myvar` on amyvar=$'\n\nx\n\n\n'
would split into 1 element. Andmyvar=''
ormyvar=$'\n\n\n'
into 0. -
jlliagre about 8 years@StéphaneChazelas Thanks Stéphane, I originally used two
set
instructions when tolf I was missing-f
but overlook the issue introduced by an edit that came later. I agree empty lines are still an issue with this approach. -
jlliagre about 8 years@BinaryZebra no problem, the issue was tricky to detect.
-
Admin about 8 yearsThe 1977 Bourne shell had no functions. I'd expect those kind of redirections wouldn't work great there either. Redirection was quite buggy back then there. It's a bit pointless trying to be portable to such an old shell anyway.
-
Admin about 8 yearsAnswer updated to fully solve the
myvar=$'\n\n\n'
problem. -
Admin about 8 yearsIIRC, It didn't support
set --
either. It may have supportedset - $var
, butset -
alone would still be the same asset
(again from vague memory). There, you'd needset x $var; shift
. -
Admin about 8 yearsTesting on a PDP11 emulator running Unix v7, it looks like
set -
worked there. The need forset x $var; shift
might have been for another shell. Note thatyash
at least doesn't supportset - $var
. -
Admin about 8 years@StéphaneChazelas I fully agre with your words: ` It's a bit pointless trying to be portable to such an old shell anyway.` .... Yes,
set --
was not there originally: set -- was not implemented originally, but came with the second release of the Bourne shell.. ... ... Yesset x $var; shift
would be the usual workaround. ... ... ... ... Thanks for all your informative comments. Bye. -
Admin about 8 years@StéphaneChazelas Where is Unix v7 (for pdp11) available?
-
Admin about 8 years
-
jlliagre about 8 years@BinaryZebra with this last edit, an empty
myvar
becomes an issue... -
jlliagre about 8 years@BinaryZebra With the last syntax, an empty variable leads to 1 (one line) while I guess the OP expects this situation to fail the test as it would fail with his/her sample script.
-
Admin about 8 yearsAh! good point. I understand you now. But that is an obvious failure of the original test. The correct question that should be answered is: "how many new lines contain the variable". If it is zero, as in
myvar=ab
, then there is "only one line". How many new lines contains an empty variable?. ... ... ... In any case, if that is really required, a test for an empty$myvar
could be added. Which I believe it shouldn't. -
Admin about 8 yearsAs is also incorrect that with that function with
myvar="ab"
is exactly the same as withmyvar=$'ab\n'
. Should a trailing newline be ignored?.