9

I have a string that is the result of some operation I have no control over. When I print this variable using echo, I get:

echo $myvar
hello

However, when I do

if [ $myvar = "hello" ]; then
    echo they are equal
else
    echo they are not equal
fi

I always get that they are not equal. I suspect this is because of a newline character.

The string also behaves strangely. When I do:

newVAR="this is my var twice: "$myvar$myvar
echo $newVAR

I get:

hellois my var twice: hello

How can I check if this is in fact due to a newline and, if so, remove it?

  • 1
    In Bash you can printf '%q\n' "$string" to get an escaped version of any string. For example: printf '%q\n' 'foo\n' -> foo\\n; printf '%q\n' $'foo\n' -> $'foo\n' – l0b0 Jul 10 '15 at 7:28
  • 1
    You're not quoting the expansion of any of your variables. If they did have any trailing whitespace, you wouldn't see it with echo $foo. Do echo "$foo" instead. – Peter Cordes Jul 10 '15 at 8:50
9

The problem is that you have an embedded Carriage-Return (CR, \r). This causes the terminal text-insertion point to kick back to the start of the line it is printing. That is why you are seeing the 'hello' at the start of the line in you $newVAR example - sed -n l displays a readable view of unprintable characters (and end of line).

var=ab$'\r'c ; echo "$var";  printf %s "$var" | sed -n l
# output:
cb
ab\rc$

You can test for it with a simple bash condition check:

[[ $var == *$'\r'* ]] && echo yes || echo no
# output:
yes

You can combine the test and fix in one step by testing for \r(s) and removing them via:

fix="${var//$'\r'/}"; echo "$var"; echo "$fix"
# output:
cb
abc

The fix uses Shell Parameter Expansion. The particular form used above is for replacing substrings based on your proovided pattern: ${parameter/pattern/string} <-- This replaces only the first found pattern with string in variable named *parameter. To replace all patterns, you just need to change the first / to //.

| improve this answer | |
  • could you explain your last bit of code? the fix=".... line? – farid99 Jul 9 '15 at 23:21
  • @farid99: explanation added to answer, Note fix can be var itself - or often you can just use the parameter expansion as-is without the need to reassign the (possibly) modified value.. – Peter.O Jul 9 '15 at 23:34
5

You can represent \r as $'\r' in bash:

if [ "$myvar" = "hello"$'\r' ]; then
    echo they are equal
else
    echo they are not equal
fi

Or chop the last \r in myvar:

if [ "${myvar%$'\r'*}" = "hello" ]; then
    echo they are equal
else
    echo they are not equal
fi
| improve this answer | |
3

Curiously, in many shells getopts is a very likely candidate for a job like this. This may seem counterintuitive at first, but if you consider that getopts' primary function is to recognize and offer up for interpretation as many specified single character command-line options as might be found in a concatenated series of same, it might begin to make a little more sense.

To demonstrate, from a bash shell:

x=$(printf '\n\r%010s\t' hello)
OPTIND=1
while  getopts : na "-$x"
do     printf %q\\n "$OPTARG"
done

$'\n'
$'\r'
\
\
\
\
\
h
e
l
l
o
$'\t'

In that way it can sometimes be convenient to allow getopts to handle the disassembly as a sort of shell auto-pilot for cases like this. When you do so, you can just screen out unwanted bytes w/ a case or [ test ] and build your string back-up from byte 1:

OPTIND=1 y=$(printf \\n\\r) z=
while  getopts : na "-$x"
do     case $OPTARG in ([!$y])
            z=$z$OPTARG
       esac
done
printf %q\\n "$z"

$'     hello\t'

Given this simple example case - and given a shell which supports the parameter expansions already elsewhere mentioned - said expansions will probably serve you better here. But I thought getopts might be worth a mention as well in case you weren't aware of its capabilities in this respect. Certainly when I learned of it I found many useful applications for it, anyway.

| improve this answer | |
0

While Bash and other shell languages are handy, sometimes it's better to use a true scripting language - like Perl. Perl can replace shell scripts that call other languages such as sed and awk as well as UNIX commands quite easily. I learned this 20+ years ago when writing C-Shell scripts which in turn called sed, awk, and various UNIX commands - before calling FORTRAN code. In Perl I would do:

chomp($myvar);   # removes the newline char

if("$myvar" eq "hello")   # string comparison
  {
  print "they are equal\n";
  }
else
  {
  print "they are not equal\n";
  }
| improve this answer | |

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.