Bash script works but strange message


59 posts   Page 1 of 3   1, 2, 3
by timmoore46 » Sat Feb 23, 2013 6:22 pm
I'm trying to use a sort of 'and' function but I'm a rank newbie to BASH

This is the truth table I'm attempting to simulare in the scipt:-

Inputs outputs an altered y called d
y z d

0 0 0
0 1 1
1 0 1
1 1 1

and it works.....

#! /bin/sh

# 23/2/13

# chmod a+x logic_003

# control c stops the program

# using font 'DejaVu Sans Mono'

while true

do

#setup Input


echo "y?"

read y

echo "z?"

read "z"

if [ $y -eq 0 ]

then a=0
# a dummy only

else
if [$z -eq 0 ]

then y=0

else y=1

fi

fi

echo "y is :-"
echo $y
echo "z is:- "
echo $z

echo " end of logic section"

sleep 3

echo " "

continue
done
______________________

But it offers an error message;-


./logic_003: 57: /./logic_003: [0: not found (for y=1 and z=0 input)

./logic_003: 57: /./logic_003: [1: not found (for y=1 and z=1 input)

____________________________________

Anybody and ideas what this message is about ?

I know I'm an idiot but ar least I'm trying to get BASH do do something useful !

Any ideas anyone... ???

:? :? :? :? :? :?

Tim
Posts: 212
Joined: Tue Jul 17, 2012 4:36 pm
by jojopi » Sat Feb 23, 2013 7:05 pm
"[" is just a silly name for the command "test". Because it is the name of a command, and not a feature of the language syntax, there must be a space between the "[" and its arguments. If you miss the space out, like "if [$z", you try to run the command "[0", which does not exist.

In my opinion it is clearer just to write:
Code: Select all
if test "$z" -eq 0; then
User avatar
Posts: 1965
Joined: Tue Oct 11, 2011 8:38 pm
by DBryant » Sat Feb 23, 2013 7:44 pm
Bash syntax is:
Code: Select all
If [ conditional expression1 ]
then
   statement1
   statement2
   .
elif [ conditional expression2 ]
then
   statement3
   statement4
.
else
   statement5
fi


I think you must have a space after the [ and one before the ] too.
Seems to work when I tried it
Posts: 279
Joined: Sat Feb 02, 2013 12:41 pm
Location: Berkshire, UK
by totoharibo » Sat Feb 23, 2013 8:41 pm
at the same time try read z not read "z"
Posts: 890
Joined: Thu Jan 24, 2013 8:43 am
by timmoore46 » Sun Feb 24, 2013 7:31 am
Many many thanks ! I really appreciate all your support !

I will amend my script and see if it behaves better !

A very happy,

:D

Tim
Posts: 212
Joined: Tue Jul 17, 2012 4:36 pm
by DBryant » Sun Feb 24, 2013 9:39 am
Just a note on the use of [.

[ is a binary, run
Code: Select all
ls -la /usr/bin | more
but just strangely named. You can see why that space is required, after all if if were call test, you would expect 'test$z' (no space) to be different from 'test $z'.

So [ (aka test) reads its arguments are does its job. The last argument (the closing ]), it simply ignores; so there is no need for a /usr/bin/]. But it too will require a space in front of it, simply because that's how arguments are separated in a shell.

And 'read z' if no different from 'read "z"', wouldn't expect if to be and it isn't in reality. However if you're new to scripting then you might want to get into the habit of enclosing strings in quotes, for example
Code: Select all
name="Dave Bryant"
printf "%s\n" $name
Dave
Bryant
printf "%s\n" "$name"
Dave Bryant

with quotes the string is printed correctly as a single arg, without it is treated as two args.
Posts: 279
Joined: Sat Feb 02, 2013 12:41 pm
Location: Berkshire, UK
by timmoore46 » Sun Feb 24, 2013 6:26 pm
Well, my logic is a bit off, but what concerns me now is how to pass the information to a 'log' file, so I can go back and look at it.

I've added 'date' to it so I've got a real time record of events,,,,,,

any ideas anyone ?


:D :D :D

Tim
Posts: 212
Joined: Tue Jul 17, 2012 4:36 pm
by DBryant » Sun Feb 24, 2013 8:15 pm
Constructs like
logFile="~/scriptLogFie.txt"
echo "$(date): Initial log record" >> $logFile


might do what you want. The >> appends the result of the echo to the specified file.

If you want to null the file at the start of the script then either of these lines at the start would do
cat /dev/null >> $logFile
echo "$(date): Initial log record" > $logFile


Note the single > in the last case.

These examples are re-directing the script's stdout to a file. There is also stderr to consider which can be routed to the same file, or to a specific error file, different from the log. But that might be more thatn you want at this point in time.

Alternatively there is the logger utility that wil inject log records into /var/log/message via UNIXs standard logger daemon - see http://unixhelp.ed.ac.uk/CGI/man-cgi?logger+1 for detail. This is more advanced but puts information into an established logging stream.
Posts: 279
Joined: Sat Feb 02, 2013 12:41 pm
Location: Berkshire, UK
by timmoore46 » Sun Feb 24, 2013 9:19 pm
Wow ! Mega Brilliant ! At this stage the simplest solution is the best ! Occam was right ! *LOL*

That was exactly what I needed ! Apart from a Tardis ! Time always is tricky ! *LOL*

:D :D :D :D :D :D

Tim
Posts: 212
Joined: Tue Jul 17, 2012 4:36 pm
by jojopi » Sun Feb 24, 2013 9:45 pm
DBryant wrote:cat /dev/null >> $logFile
That does nothing. It does write nothing to the file, but you opened the file for appending, so the existing contents remain. The canonical way to truncate a file to zero bytes is:
Code: Select all
: > $logFile
Here, ":" is a silly name for "true", which produces no output.

By the way, in scripts it is better to use "$HOME" instead of "~". "~" works in most shells, but it is non-standard.
User avatar
Posts: 1965
Joined: Tue Oct 11, 2011 8:38 pm
by timmoore46 » Mon Feb 25, 2013 7:37 am
I tried this:-

logfile="test.log"

echo "$date" >> $test.log

and it does not work.

Obviously I'm missed something vital !

:( :( :( :(

Tim
Posts: 212
Joined: Tue Jul 17, 2012 4:36 pm
by DBryant » Mon Feb 25, 2013 7:55 am
Clue: Look where your re-directing the output to!

I defined a variable, initialised to the name of a file; something you might put at the top of the script and re-use through the script. Then you re-direct to that; you've re-written the name of the file, prepended with a dollar, as if its a variable. Bash good not this is. Take another at the first code block in my earlier posting.

There was a typo in that first posting; to null a file then it should have be a single > as in
Code: Select all
cat /dev/null > $logFile


Yes, there are other ways of doing this (as in ': > $logFile'), one just have to decide what is your comfortable way of doing things. As this stage, less cryptic looks a better way to go. But then one man's cryptic is another man's ... Fortunately (or not) coding standards are unenforced in the home brew domain. ;)
Posts: 279
Joined: Sat Feb 02, 2013 12:41 pm
Location: Berkshire, UK
by timmoore46 » Mon Feb 25, 2013 6:05 pm
Wow ! removed the $ from the 2nd line and it worked !

Many many thanks! Especially for your patience.

As you can tell my understanding of BASH is close to non existent !

I'll play with this and see if I can get work in my mail control program !

:D :D :D :D :D :D

Tim
Posts: 212
Joined: Tue Jul 17, 2012 4:36 pm
by timmoore46 » Mon Feb 25, 2013 6:19 pm
logfile="control_004.log"
echo "$(date)" >>control_004.log

date


saves the date stamp fine.

The next challenge is to get anything sent to the console into the logfile too...

:D :D :D :D :D

Tim
Posts: 212
Joined: Tue Jul 17, 2012 4:36 pm
by DBryant » Mon Feb 25, 2013 7:23 pm
You've not got it have you!

The logFile variable , as you use it, is totally redundant because you don't use it!
Your code should be this exaclty:
Code: Select all
logfile="control_004.log"
echo "$(date)" >> $logFile


The assumption was that you would have many log records written in your script. In this scenario, if you decide to call the logfile something else, you just have to change one line (nicely poistioned at the top of the script). Otherwise you'd have to find everying log line and edit if with the new name.

You need to look tee, see http://unixhelp.ed.ac.uk/CGI/man-cgi?tee.

So in your case
Code: Select all
logfile="control_004.log"
echo "$(date)" | tee -a  $logFile


the -a is important so as to append rather than overwrite.
Posts: 279
Joined: Sat Feb 02, 2013 12:41 pm
Location: Berkshire, UK
by timmoore46 » Mon Feb 25, 2013 8:01 pm
Many thanks again, especially for your patience !

I will try it out tomorrow.

:D :D :D :D :D :D

Tim
Posts: 212
Joined: Tue Jul 17, 2012 4:36 pm
by timmoore46 » Tue Feb 26, 2013 9:12 am
$logFile

The upper case F

does that have significance ?

what would happen if it was :-

$logfile

I'm just paranoid about anything as unforgiving as assembler or BASH.

:D :D :D

Tim

logfile="control_004.log"
Posts: 212
Joined: Tue Jul 17, 2012 4:36 pm
by DBryant » Tue Feb 26, 2013 10:00 am
None at all. There are several 'standards', styles might be a better term for naming variables, where an effort is made to improve legibility, given that including spaces is not really a preferred option.

One is two capitalize words (after the first one) and hence logFile. Another would be to insert underscores, so this would be log_file. Another one would be to do nothing, as in logfile.

Just be consistent throughout your script, don't expect logfile and logFile to be interchangeable, they are not. And developing a style is good because you may want to slice your script across several files, such that functions can be used in other projects. Then a definite style will benefit your development.

All are valid, depends on ones attitude to this things. Once a script gets big, any slight advantage becomes very useful. Even using logfile instead of just 'l' is an improvement, simply because you can use your editor to search out logfile instances better than l instances.

Shells tend to read variable names up until the first invalid character so another thing you might come across is ${logFile} i.e delimited by {}. Tends to be used when you're printing plurals and you want that additional s; so "${logFile}s" works as you might intend but NOT $logFiles which is rarely correct. And yes, there are other ways of handling this scenario.

Not sure that I'd agree that bash is particularly unforgiving.

Since bash is text based, and our eye/brain is well tuned to processing text, we assume that anything we write is perfectly legible. By legible I mean the mechanics, of space, the usage of capitaliz/sation, sleping, apostrophe's and so on, which we can parse and interpret in our brains to get the underlying sense. And then we still get it wrong on occasion. We get into the habit that these things are unimportant, but they are, and particularly to command line shells like bash, csh and the rest of them. 'Particularly' because they really need a pre-processor to sanitize the text before its thrown at the shell interpreter, exactly what a compiler might do in part in the wonderful world of Java for example.

Nuff said :!:
Posts: 279
Joined: Sat Feb 02, 2013 12:41 pm
Location: Berkshire, UK
by timmoore46 » Wed Feb 27, 2013 6:51 am
code was:-

logfile="control_004.log"
echo "$(date)" | tee -a $logFile

and the hope was all the screen output would wind up being added to a file.

the output that actually is out put to the screen is:-

quote

root@raspberrypi:~# ./test_002
Wed Feb 27 06:43:28 UTC 2013
y is :-
1
z is :-
0

Wed Feb 27 06:43:34 UTC 2013
y is :-
1
z is :-
0

Wed Feb 27 06:43:40 UTC 2013
y is :-
1
z is :-
0
end quote

_________

using ls and nano I can't find any file with that in it.

so what is the name of the file I'm looking for and where is it (which directory) ?

I am operating in the root directory because it makes chmod very easy to use.

( I'll agree with you on BASH does give error messages but I'd hate to make a mistake using DD)

:D :D :D

Tim
Posts: 212
Joined: Tue Jul 17, 2012 4:36 pm
by DBryant » Wed Feb 27, 2013 8:06 am
logfile and logFile!!!! To quote my previous response
don't expect logfile and logFile to be interchangeable


Your first lines have to be
logFile="control_004.log"
echo "$(date)" | tee -a $logFile

where I've highlighted the two parts that must agree.

As it stands $logFile is empty and for tee the file argument is optional (see the man page http://unixhelp.ed.ac.uk/CGI/man-cgi?tee where is enclosed in [] (as in [FILE]) meaning optional). So in your code tee accepts stdin, write to stdout, and nothing else; no file with no name, zilch, zippo.

So change the line
Code: Select all
 logfile="control_004.log" => [b]logFile[/b]="control_004.log"
.

I think you malign dd, it comes down to accuracy of the user. It expects a valid src and a valid destination, switch them around and all hell breaks lose. Driving on the right (in the UK) is equally catastrophic. As in most cases what we want is "do what I mean, not what I say" but shells, and computers in general, don't work like that
Posts: 279
Joined: Sat Feb 02, 2013 12:41 pm
Location: Berkshire, UK
by timmoore46 » Wed Feb 27, 2013 8:31 am
code:-

logfile="control_004.log" => logFile="control_004.log"
echo "$(date)" | tee -a $logFile

yields


./test_002: 13: ./test_002: cannot create logFile=control_004.log: Directory nonexistent


would be be easier to follow if the name was changed of 'logFile' to 'example_001' ?

have I made an idiot typo ?

:? :? :? :? :?

Tim
Posts: 212
Joined: Tue Jul 17, 2012 4:36 pm
by DBryant » Wed Feb 27, 2013 8:48 am
The => means 'becomes'!

Your code should read
Code: Select all
logFile="control_004.log"
echo "$(date)" | tee -a $logFile
Posts: 279
Joined: Sat Feb 02, 2013 12:41 pm
Location: Berkshire, UK
by timmoore46 » Wed Feb 27, 2013 8:56 am
Many thanks, I'll try that.

a small mystery

nano control_004.log

yields

Mon Feb 25 18:08:38 UTC 2013
Mon Feb 25 18:08:44 UTC 2013
Mon Feb 25 18:08:51 UTC 2013
Mon Feb 25 18:08:57 UTC 2013
Mon Feb 25 18:09:03 UTC 2013
Mon Feb 25 18:09:09 UTC 2013
Mon Feb 25 18:13:15 UTC 2013

Mon Feb 25 18:13:21 UTC 2013

Mon Feb 25 18:13:27 UTC 2013
____

and

cat control_004.log

yields



Wed Feb 27 08:47:59 UTC 2013

Wed Feb 27 08:48:05 UTC 2013

____

?????

Many many thanks for your support !

:D :D :D :D :D :D :D

Tim
Posts: 212
Joined: Tue Jul 17, 2012 4:36 pm
by timmoore46 » Wed Feb 27, 2013 9:24 am
logFile="control_004.log"
echo "$(date)" | tee -a $logFile


root@raspberrypi:~# cat control_004.log


Wed Feb 27 09:04:22 UTC 2013

Wed Feb 27 09:04:28 UTC 2013


___________________________

the rest of it is missing.

viz:-
start quote

y is :-
1
z is :-
0
end quote

????

:D :D

Tim
Posts: 212
Joined: Tue Jul 17, 2012 4:36 pm
by DBryant » Wed Feb 27, 2013 9:26 am
You are looking at 2 different files I would guess.

What directories are you invoking the nano and cat commands from?

Why not just tidy up all log files and start again? The script should be run as the pi user, within pi's filesystem and so on. Running within the root directory just because of perms is not a good habit to get into.

To find all files then
Code: Select all
sudo find / -name control_004.log
will scan the whole file system. Its run as the superuser so it can wander over the whole of the filesystem without any permissions issue. The / is the root os the filesystem, so the command will recursively span the entire directory tree.

You can rm then all with:
Code: Select all
sudo find / -name control_004.log -exec rm {} \;

You are then in a position to start again, now your code is doing vaguely the right thing.

In the above commands you could replace the / with /home/pi, assuming you were disciplined to only work within the pi accounts filesystem and only run your script as the pi user. The commands are then (we no longer need the sudo):
Code: Select all
find /home/pi -name control_004.log
find /home/pi -name control_004.log -exec rm {} \;


As a final comment, if it were me, then I'd construct logFile to include the directory location too as follows
Code: Select all
logDir="/home/pi/logs"
logName="control_004.log"
logFile=${logDir}/${logName}

this gives great ease to modify the directory and the name of log file. In the future, you might then decide to make logDir depend on the date, so you have logs stored in a daily (named) folder. This can be overkill etc. but in 15 years time when changes are to be made, it all becomes a breeze.
Posts: 279
Joined: Sat Feb 02, 2013 12:41 pm
Location: Berkshire, UK