Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

See exact content of bash variable? (hexdump doesn't help)

Tags:

bash

hex

quoting

So I have a problem below, but my question is more generic - how to see exact content of memory referenced by bash variable to understand why they don't match:

# [[ $c1 == $c ]] || echo nope
nope
# [[ $c1 == "bkup dt" ]] || echo nope
# [[ $c == "bkup dt" ]] || echo nope
nope
# hexdump -C <<<$c
00000000  62 6b 75 70 20 64 74 0a                           |bkup dt.|
00000008
# hexdump -C <<<$c1
00000000  62 6b 75 70 20 64 74 0a                           |bkup dt.|
00000008
# [ "$c1" = "$c" ] || echo nope
nope
# [ ! "$c1" = "$c" ] || echo nope

Or does it look like a bug? I can repeat the problem with:

$ cd /tmp
$ mkdir aaa
$ echo 2 > aaa/1
$ echo 2 > aaa/2
$ c=$(ls -A aaa)
$ [[ $c == $(echo $c) ]] || echo not equal
not equal
$ hexdump -C <<<$c
00000000  31 20 32 0a                                       |1 2.|
00000004
$ hexdump -C <<<$(echo $c)
00000000  31 20 32 0a                                       |1 2.|
00000004
$ c1="1 2"
$ [[ $c1 == $(echo $c1) ]] || echo not equal
$ [[ $c1 == $(echo $c) ]] || echo not equal
$ [[ $c1 == $c ]] || echo not equal
not equal
like image 730
noonex Avatar asked Dec 15 '22 01:12

noonex


1 Answers

The best thing to inspect the content of a variable is to use declare -p:

$ c="1 2"
$ declare -p c
declare -- c="1 2"

Note that your tests are wrong because you're missing out quotes in your variable expansions!

Look:

$ c="1  2" # with two spaces
$ declare -p c
declare -- c="1  2"
$ echo $c
1 2
$ echo "$c"
1  2
$ d=$(echo $c)
$ declare -p d
1 2

You must quote every single variable expansion, unless you really want to have word splitting and pathname expansion applied to them! (and usually, you certainly don't want that to happen).

Even with your hexdump strategy you need quotes:

$ c="1  2" # two spaces
$ hexdump <<< $c
00000000  31 20 32 0a                                       |1 2.|
00000004
$ hexdump <<< "$c"
00000000  31 20 20 32 0a                                    |1  2.|
00000005

What you're experiencing is exactly this:

$ mkdir aaa; touch aaa/{1,2}
$ c=$(ls -A aaa)
$ declare -p c
declare -- c="1
2"
$ # see? there's a new line between the files.
$ echo $c
1 2
$ echo "$c"
1
2
$ # Use quotes!

Sometimes declare -p will not quite show spaces properly. In this case you can use printf like so:

$ c=$'    \n'
$ declare -p c
declare -- c="    
"
$ # there are spaces, but you can't see them
$ printf '%q\n' "$c"
$'    \n'

The declare strategy is also nice as you can inspect arrays and functions too:

$ a=( one two "three four" )
$ declare -p a
declare -a a='([0]="one" [1]="two" [2]="three four")'
$ declare -A h=( [one]=1 [two]=2 )
$ declare -p h
declare -A h='([one]="1" [two]="2" )'
$ f() { echo hello; } > somewhere > >(over the rainbow)
$ declare -pf f
f () 
{ 
    echo hello
} > somewhere 2> >(over the rainbow)
$ # You need also the -f switch to target functions

You also have access to the flags of the variables:

$ declare -litux hello=world
$ declare -p hello
declare -itx hello="0"
$ # Have fun!
like image 119
gniourf_gniourf Avatar answered Dec 27 '22 08:12

gniourf_gniourf