Strange Behaviour of `bash` with echo statements

Solution Verified - Updated -

Environment

  • Red Hat Enterprise Linux (RHEL) 5.8
  • bash

Issue

  • On Red Hat Enterprise Linux 5.8, following commands are executed.
# export temp_tag_value=`echo "[2405:201:fffb:8a::4]" | sed 's/\//\\\\\//g'`
# echo $temp_tag_value
  • On one of the servers, it works fine, but on other server it returns a vague value as 'a' or '1'.
  • It seems that the command echo $temp_tag_value returns name of a file named a or 1 which is present in the same directory, and if that file is removed, then it returns the expected output.
  • Why bash is behaving strangely?

Resolution

  • This is expected behaviour. variables supplied as command parameters without quotes are subject to shell expansions including the pathname expansion. In order to prevent pathname expansion, embrace the variable with "" (double quotes).
  • From man bash
 EXPANSION
       Expansion is performed on the command line after it has been split into
       words.  There are seven kinds of expansion performed: brace  expansion,
       tilde  expansion,  parameter  and variable expansion, command substitu-
       tion, arithmetic expansion, word splitting, and pathname expansion.

       The order of expansions is: brace expansion, tilde  expansion,  parame-
       ter,  variable  and arithmetic expansion and command substitution (done
       in a left-to-right fashion), word splitting, and pathname expansion.
  • So the string "[2405:201:fffb:8a::4]" is expanded to file-names consisting of exactly one character from the [012458afb:] set in case there are such files present in current working directory. If there's no such named file in current directory, the original string is kept unexpanded.
  • To prevent value of $temp_tag_value variable to be subject of pathname expansion, use
# echo "$temp_tag_value"

instead of

# echo $temp_tag_value

Root Cause

  • This is expected behaviour - shell pathname expansion feature. This feature applies not only to bash but to other shells, such as ksh as well.

Diagnostic Steps

To Reproduce:

  • When export is done, the echo statement is taking a instead of [2405:201:fffb:8a::4], see below.
[root@localhost ~]# export temp_tag_value=`echo "[2405:201:fffb:8a::4]" | sed 's/\//\\\\\//g'`
[root@localhost ~]# echo $temp_tag_value
[2405:201:fffb:8a::4]

[root@localhost ~]# touch a

[root@localhost ~]# echo "[2405:201:fffb:8a::4]" | sed 's/\//\\\\\//g'
[2405:201:fffb:8a::4]

[root@localhost ~]# ls a
a
[root@localhost ~]# echo "[2405:201:fffb:8a::4]" | sed 's/\//\\\\\//g'
[2405:201:fffb:8a::4]

[root@localhost ~]# export new="echo "[2405:201:fffb:8a::4]" | sed 's/\//\\\\\//g'"
[root@localhost ~]# echo $new
echo a | sed 's/\//\\\//g'                    <======== see here, [2405:201:fffb:8a::4] is replaced by a here. 
  • If we remove a, and create b, then it will display b.
[root@localhost ~]# rm -rf a
[root@localhost ~]# touch b
[root@localhost ~]# export temp_tag_value=`echo "[2405:201:fffb:8a::4]" | sed 's/\//\\\\\//g'`
[root@localhost ~]# echo $temp_tag_value
b
[root@localhost ~]# touch c
[root@localhost ~]# export temp_tag_value=`echo "[2405:201:fffb:8a::4]" | sed 's/\//\\\\\//g'`
[root@localhost ~]# echo $temp_tag_value
b           <<<<<<<<<==== output is b because in [2405:201:fffb:8a::4] there is no c character, there is only a, b and f available.
[root@localhost ~]# rm b
rm: remove regular empty file `b'? y
  • Now try with f
[root@localhost ~]# rm c
rm: remove regular empty file `c'? y
[root@localhost ~]# touch f
[root@localhost ~]# export temp_tag_value=`echo "[2405:201:fffb:8a::4]" | sed 's/\//\\\\\//g'`
[root@localhost ~]# echo $temp_tag_value
f

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.

Comments