Difference between pages "Find out where configuration changes are stored" and "What does "unary operator expected" mean"

From Linuxintro
(Difference between pages)
imported>ThorstenStaerk
 
imported>ThorstenStaerk
 
Line 1: Line 1:
You may ask yourself "where are my [[configuration]] settings stored". The reason why you want to know is may be that you are the administrator and want your users to have some specific options set. This article introduces a methodology how to identify the places of configuration setting on the example of the [[program]] konsole.
+
When you work with Linux scripts on the command line, you will sometimes get an error message saying
 +
unary operator expected
 +
And you may wonder what this means. To give you an example, let's write a short bash script.
  
Whenever I set up a computer, I start konsole and change its settings. I choose Settings -> Configure Current Profile -> Tabs -> "Show 'New Tab' and 'Close Tab' buttons in tab bar". Today I wanted to write a script to do this configuration change for me. The most important question is - where is this setting being saved?
+
= The script =
 +
Just copy and paste the lines below into a Linux Shell:
 +
[[cat]] >test.sh<<EOF
 +
[[echo]] "how is your name? "
 +
read name
 +
if [ $name = "Thorsten" ]; then echo "I know you"; fi
 +
EOF
 +
chmod 777 test.sh
 +
After you did this, you have a script test.sh that will ask you for your name and say "I know you" if your name is Thorsten. You can call the script using the [[command]]
 +
./test
 +
Now if you don't enter a name and just press enter you will get this:
 +
# ./test.sh
 +
how is your name?
 +
 +
./test.sh: line 3: [: =: unary operator expected
 +
This is clearly a problem in line 3. $name is replaced by ''nothing'' when the shell executes the line. So the remainder of the line reads
 +
if [ = "Thorsten" ]; then echo "I know you"; fi
 +
Which does not work because you cannot compare ''nothing'' with "Thorsten".
  
= The strace approach =
+
= The solution =
I could find this out using the command
+
There is a simple trick to avoid this kind of error messages already when programming. For example if you add an "x" left and right next to the equal sign in line 3:
  strace -ffe open konsole
+
  if [ x$name = "xThorsten" ]; then echo "I know you"; fi
[[strace]] is a cool [[command]] that shows you every syscall invoked by a program (in the above case konsole). When called with the -e open argument, it will only show the open syscalls. This gives you a powerful tool into your hands: A monitor which files are read and/or modified by a program. The output will read like this:
+
The shell may still replace $name by ''nothing'', but then the x will stay and the command will be after evaluation:
[pid 29951] open("/etc/localtime", O_RDONLY) = 3
+
  if [ x = "xThorsten" ]; then echo "I know you"; fi
[pid 29951] open("/etc/kde4rc", O_RDONLY|O_CLOEXEC) = 3
+
And there will not be an error message any longer.
[pid 29951] open("/root/.kde4/share/config/kdeglobals", O_RDONLY|O_CLOEXEC) = 3
 
The -ff argument is needed so strace still follows spawning processes; for more information, read [http://man-wiki.net/index.php/1:strace strace's man page].
 
  
So I did [[open a console]], entered
+
= Outlook =
strace -ffe open konsole
+
You can also debug the script line-by-line using bashdb. Bashdb shows all commands that are being executed, just like [[gdb]] or [[strace]], but for bash scripts:
A konsole window popped up and I chose Settings -> Configure Current Profile -> Tabs -> "Show 'New Tab' and 'Close Tab' buttons in tab bar". When I clicked on "Apply", I found a line saying
+
<pre>
[pid 29951] open("/root/.kde4/share/apps/konsole/Shell.profile", O_RDONLY|O_CLOEXEC) = 16
+
tstaerk@ubuntu:~$ bashdb test.sh
And I could verify my changes go to /root/.kde4/share/apps/konsole/Shell.profile:
+
bashdb debugger, release 4.2-0.6
# [[cat]] /root/.kde4/share/apps/konsole/Shell.profile
 
[...]
 
ShowNewAndCloseTabButtons=false
 
[...]
 
  
= The find approach =
+
Copyright 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010 Rocky Bernstein
I started konsole, chose Settings -> Configure Current Profile -> Tabs -> "Show 'New Tab' and 'Close Tab' buttons in tab bar" -> Apply. Then I typed a command to find all files newer than 0.01 days:
+
This is free software, covered by the GNU General Public License, and you are
cd
+
welcome to change it and/or distribute copies of it under certain conditions.
[[find]] . -ctime -0.01
 
And I found the output
 
./.kde4/share/apps/konsole/Shell.profile
 
This means my configuration changes were saved in the file .kde4/share/apps/konsole/Shell.profile.
 
  
[[Category:Geeky]]
+
(/home/tstaerk/test.sh:1):
 +
1:      echo "how is your name? "
 +
bashdb<0> step
 +
how is your name?
 +
(/home/tstaerk/test.sh:2):
 +
2:      read name
 +
bashdb<1> step
 +
Thorsten
 +
(/home/tstaerk/test.sh:3):
 +
3:      if [ = "Thorsten" ]; then echo "I know you"; fi
 +
bashdb<2> step
 +
test.sh: line 3: [: =: unary operator expected
 +
(/usr/bin/bashdb:1):
 +
1:      #!/bin/bash
 +
bashdb<3> step
 +
Debugged program terminated normally. Use q to quit or R to restart.
 +
bashdb<4>
 +
</pre>
 +
 
 +
= See also =
 +
* [[troubleshooting]]
 +
* [[error messages]]

Revision as of 08:23, 21 December 2011

When you work with Linux scripts on the command line, you will sometimes get an error message saying

unary operator expected

And you may wonder what this means. To give you an example, let's write a short bash script.

The script

Just copy and paste the lines below into a Linux Shell:

cat >test.sh<<EOF
echo "how is your name? "
read name
if [ $name = "Thorsten" ]; then echo "I know you"; fi
EOF
chmod 777 test.sh

After you did this, you have a script test.sh that will ask you for your name and say "I know you" if your name is Thorsten. You can call the script using the command

./test

Now if you don't enter a name and just press enter you will get this:

# ./test.sh 
how is your name? 

./test.sh: line 3: [: =: unary operator expected

This is clearly a problem in line 3. $name is replaced by nothing when the shell executes the line. So the remainder of the line reads

if [ = "Thorsten" ]; then echo "I know you"; fi

Which does not work because you cannot compare nothing with "Thorsten".

The solution

There is a simple trick to avoid this kind of error messages already when programming. For example if you add an "x" left and right next to the equal sign in line 3:

if [ x$name = "xThorsten" ]; then echo "I know you"; fi

The shell may still replace $name by nothing, but then the x will stay and the command will be after evaluation:

 if [ x = "xThorsten" ]; then echo "I know you"; fi

And there will not be an error message any longer.

Outlook

You can also debug the script line-by-line using bashdb. Bashdb shows all commands that are being executed, just like gdb or strace, but for bash scripts:

tstaerk@ubuntu:~$ bashdb test.sh 
bashdb debugger, release 4.2-0.6

Copyright 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010 Rocky Bernstein
This is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.

(/home/tstaerk/test.sh:1):
1:      echo "how is your name? "
bashdb<0> step
how is your name? 
(/home/tstaerk/test.sh:2):
2:      read name
bashdb<1> step
Thorsten
(/home/tstaerk/test.sh:3):
3:      if [  = "Thorsten" ]; then echo "I know you"; fi
bashdb<2> step
test.sh: line 3: [: =: unary operator expected
(/usr/bin/bashdb:1):
1:      #!/bin/bash
bashdb<3> step
Debugged program terminated normally. Use q to quit or R to restart.
bashdb<4> 

See also