LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Bash script gives weird output (https://www.linuxquestions.org/questions/linux-newbie-8/bash-script-gives-weird-output-927936/)

jonaskellens 02-06-2012 01:47 PM

Bash script gives weird output
 
Hello,

when executing the following bash script :

Code:

echo "1"
CheckMainServer=$(/usr/bin/sipsak -vv -s sip:yo7@${SIPserver} -c sip:yo7@${SIPserver} --password 2aHOGrI)
echo "2"
echo $CheckMainServer
echo "3"

The output on CLI is as followed :

Quote:

[root@jonas Desktop]# sh bashscript.sh
1
2
3211988943~ 3211988947~ 952.pdf app_voicemail.c~ b2evolution bashscript.sh BusinessCard decl2009.pdf Deploying_OpenLDAP.pdf ask extension Fax faxrates.sql~ sound.jpg test2.csv test2.csv~ test.csv test.csv~ testmailing.svg test.ods test.pdf tmp_ldap~ Unreachable.txt Webmin-htb WhiteandOrangeBlogTheme SIP/2.0 404 Not Found final received
The last "SIP/2.0 404 Not Found final received" is a part of the output that I expect... but all the rest ?!

Why are my Desktop files displayed ?

Tinkster 02-06-2012 02:03 PM

I don't know ... but what does
Code:

/usr/bin/sipsak -vv -s sip:yo7@${SIPserver} -c sip:yo7@${SIPserver} --password 2aHOGrI
all by itself tell you?



Cheers,
Tink

jonaskellens 02-06-2012 02:13 PM

Quote:

Originally Posted by Tinkster (Post 4595303)
I don't know ... but what does
Code:

/usr/bin/sipsak -vv -s sip:yo7@${SIPserver} -c sip:yo7@${SIPserver} --password 2aHOGrI
all by itself tell you?

Executing this command on CLI just gives the desired output. Nothing more.

When executing this in bash script, it gives all the weird Desktop-information...

Dark_Helmet 02-06-2012 02:16 PM

You missed Tinkster's point :)

He wanted you to paste the exact output of the command.

It's likely that your command's output includes an asterisk. Hence, when you:
Code:

echo $CheckMainServer
the shell will expand the asterisk as a filename wildcard--which results in a list of your files in the current directory.

It may not be an asterisk, but some other character that is interpreted by the shell. I just used the asterisk as an example.

EDIT:
You can avoid some bash substitution problems by quoting variables. For instance:
Code:

echo "$CheckMainServer"

devilboy09 02-06-2012 02:19 PM

is this your hole script file? where is the shebang?
and please do tell what are you trying to do with this script.
tanX

jonaskellens 02-06-2012 02:23 PM

Quote:

Originally Posted by Dark_Helmet (Post 4595317)
EDIT:
You can avoid some bash substitution problems by quoting variables. For instance:
Code:

echo "$CheckMainServer"

Problem solved by using : echo "$CheckMainServer"

Thanks !

jonaskellens 02-08-2012 03:16 AM

I have another question :

CheckMainServerOutput = "final received"

When executing this :
Code:

if [ "$CheckMainServerOutput" =~ "*ms*" ] || [ "$CheckMainServerOutput" =~ "*32.43.26*" ]; then
I get the following notice :
Quote:

bashscript.sh: line 15: [: =~: binary operator expected
bashscript.sh: line 15: [: =~: binary operator expected
So what is the correct syntax ?

catkin 02-08-2012 03:55 AM

Quote:

Originally Posted by jonaskellens (Post 4596870)
So what is the correct syntax ?

Remove the double quotes around the regular expression?

Cedrik 02-08-2012 04:30 AM

Code:

# .  : match any character
# *  : previous char is present zero or more times
# \. : match a dot

if [[ "$CheckMainServerOutput" =~ .*ms.* ]] || [[ "$CheckMainServerOutput" =~ .*32\.43\.26.* ]]; then

BTW, a pattern matching looks like:
Code:

if [[ "$CheckMainServerOutput" == *ms* ]] || [[ "$CheckMainServerOutput" == *32.43.26* ]]; then

Tinkster 02-08-2012 10:15 AM

Quote:

Originally Posted by Cedrik (Post 4596914)
Code:

# .  : match any character
# *  : previous char is present zero or more times
# \. : match a dot

if [[ "$CheckMainServerOutput" =~ .*ms.* ]] || [[ "$CheckMainServerOutput" =~ .*32\.43\.26.* ]]; then

BTW, a pattern matching looks like:
Code:

if [[ "$CheckMainServerOutput" == *ms* ]] || [[ "$CheckMainServerOutput" == *32.43.26* ]]; then


No, it doesn't. Pattern matching uses =~, and uses an actual
regex-engine, so to match a literal period .*32\.43\.26.* is the
correct form.


Try this:
Code:

if [[ "$CheckMainServerOutput" =~ *ms*  ||  "$CheckMainServerOutput" =~ *32.43.26* ]]; then
Cheers,
Tink

catkin 02-08-2012 11:18 AM

Quote:

Originally Posted by Tinkster (Post 4597118)
Code:

if [[ "$CheckMainServerOutput" =~ *ms*  ||  "$CheckMainServerOutput" =~ *32.43.26* ]]; then

Is that what you intended, Tinkster? AFAIK it means "$CheckMainServerOutput" contains *m followed by any number of the character s or *32 followed by any character ...

On further reflection, the reason bash generated syntax errors on interpreting
Code:

if [ "$CheckMainServerOutput" =~ "*ms*" ] || [ "$CheckMainServerOutput" =~ "*32.43.26*" ]; then
is that the =~ comparison operator is not valid in the [ ... ] test form, only in the [[ ... ]] form.

Cedrik 02-08-2012 11:51 AM

Quote:

Originally Posted by Tinkster (Post 4597118)
No, it doesn't. Pattern matching uses =~, and uses an actual
regex-engine, so to match a literal period .*32\.43\.26.* is the
correct form.


Try this:
Code:

if [[ "$CheckMainServerOutput" =~ *ms*  ||  "$CheckMainServerOutput" =~ *32.43.26* ]]; then
Cheers,
Tink

Maybe I used the wrong term ("pattern") but:
Code:

[[ "linux" == *in* ]] && echo ok
ok
[[ "linux" =~ *in* ]] && echo ok
<nothing>


Tinkster 02-08-2012 12:35 PM

Quote:

Originally Posted by catkin (Post 4597164)
Is that what you intended, Tinkster? AFAIK it means "$CheckMainServerOutput" contains *m followed by any number of the character s or *32 followed by any character ...

My intention was to quote the string the OP used. I think I succeeded.
Whether the original string is what the OP really wanted I don't know.

Quote:

Originally Posted by catkin (Post 4597164)
On further reflection, the reason bash generated syntax errors on interpreting
Code:

if [ "$CheckMainServerOutput" =~ "*ms*" ] || [ "$CheckMainServerOutput" =~ "*32.43.26*" ]; then
is that the =~ comparison operator is not valid in the [ ... ] test form, only in the [[ ... ]] form.

Well spotted. That's what I changed above.


Cheers,
Tink

Tinkster 02-08-2012 12:37 PM

Quote:

Originally Posted by Cedrik (Post 4597210)
Maybe I used the wrong term ("pattern") but:
Code:

[[ "linux" == *in* ]] && echo ok
ok
[[ "linux" =~ *in* ]] && echo ok
<nothing>


Remove the leading aster; it's not a valid regex.

Cedrik 02-08-2012 12:45 PM

man bash:
Code:

...
 [[ expression ]]
...
              When the == and != operators are used, the string to  the  right
              of the operator is considered a pattern and matched according to
              the rules described below under Pattern Matching.  If the  shell
              option  nocasematch  is  enabled, the match is performed without
              regard to the case of alphabetic characters.  The  return  value
              is  0 if the string matches (==) or does not match (!=) the pat-
              tern, and 1 otherwise.  Any part of the pattern may be quoted to
              force it to be matched as a string.
              ...
              An  additional  binary operator, =~, is available, with the same
              precedence as == and !=.  When it is used,  the  string  to  the
              right  of the operator is considered an extended regular expres-
              sion and matched accordingly (as in regex(3)).  The return value
              is 0 if the string matches the pattern, and 1 otherwise.
...
      Pattern Matching

      Any character that appears in a pattern, other than the special pattern
      characters described below, matches itself.  The NUL character may  not
      occur  in  a pattern.  A backslash escapes the following character; the
      escaping backslash is discarded when  matching.  The  special  pattern
      characters must be quoted if they are to be matched literally.
             
      The special pattern characters have the following meanings:
             
      *      Matches  any  string, including the null string.
...

So I was right, this is pattern matching:
Code:

if [[ "$CheckMainServerOutput" == *ms* ]] || [[ "$CheckMainServerOutput" == *32.43.26* ]]; then

Tinkster 02-08-2012 01:51 PM

Quote:

Originally Posted by Cedrik (Post 4597283)
man bash:
Code:

...
 [[ expression ]]
...
              When the == and != operators are used, the string to  the  right
              of the operator is considered a pattern and matched according to
              the rules described below under Pattern Matching.  If the  shell
              option  nocasematch  is  enabled, the match is performed without
              regard to the case of alphabetic characters.  The  return  value
              is  0 if the string matches (==) or does not match (!=) the pat-
              tern, and 1 otherwise.  Any part of the pattern may be quoted to
              force it to be matched as a string.
              ...
              An  additional  binary operator, =~, is available, with the same
              precedence as == and !=.  When it is used,  the  string  to  the
              right  of the operator is considered an extended regular expres-
              sion and matched accordingly (as in regex(3)).  The return value
              is 0 if the string matches the pattern, and 1 otherwise.
...
      Pattern Matching

      Any character that appears in a pattern, other than the special pattern
      characters described below, matches itself.  The NUL character may  not
      occur  in  a pattern.  A backslash escapes the following character; the
      escaping backslash is discarded when  matching.  The  special  pattern
      characters must be quoted if they are to be matched literally.
             
      The special pattern characters have the following meanings:
             
      *      Matches  any  string, including the null string.
...

So I was right, this is pattern matching:
Code:

if [[ "$CheckMainServerOutput" == *ms* ]] || [[ "$CheckMainServerOutput" == *32.43.26* ]]; then

Of course it is ... and so is =~ (coincidentally described in the same bit
of bash's man-page that you quoted), which you claimed, by way of different example
Quote:

BTW, a pattern matching looks like:
wasn't pattern matching.


Cheers,
Tink

Cedrik 02-08-2012 01:56 PM

Ok, I admit I wasn't clear :)

jonaskellens 02-12-2012 08:25 AM

Hello,

so far I was helped very well with problems that occurred.

Now I have a third question :
Code:

echo "before"
$StartProg=$(/sbin/service prog start)
echo $StartProg
echo "after"

gives output :
Quote:

before
bashscript.sh: line 14: =Starting: command not found

But I notice that the service "prog" has in fact started !

Why does bash report "command not found" ?
Is there something wrong with my syntax ?

When I execute /sbin/service prog start on CLI, then output is normal :
Quote:

Starting prog: [ OK ]

catkin 02-12-2012 08:49 AM

When bash processes $StartProg=$(/sbin/service prog start), it:
  1. Runs /sbin/service prog start (starting the service) and substitutes its output into the line leaving $StartProg=Starting <whatever>
  2. Substitutes the value of $StartProg which is nothing, leaving =Starting <whatever>
  3. Runs that as a command, resulting in the error message you see.

jonaskellens 02-12-2012 09:55 AM

But I read all over the internet that the syntax $(command) is the correct way of executing a command.

How do I then get normal output of the command so that the rest of the bashscript can continue ?

Dark_Helmet 02-12-2012 12:05 PM

Quote:

Originally Posted by jonaskellens
But I read all over the internet that the syntax $(command) is the correct way of executing a command.

It is, but the problem is not with the $( ... ) construct.

Re-read point #2 in catkin's message.

In bash, when you want to use the value of a variable, you prefix the variable name with a '$'.
Code:

echo "This is the value: $variableValue"
When you want to assign a value to a variable, you do not prefix the variable name with a '$'.
Code:

variableValue="This is the assigned value"
This is different from other languages (e.g. PHP) where the '$' prefixes every variable reference (assignment or substitution).

jonaskellens 02-12-2012 01:19 PM

OK I see. I did not notice this before. In the rest of my script I did not make this mistake.

The error-message "=Starting: command not found" is gone, that's good !

However, even with StartProg=$(/sbin/service prog start) I still get no output and the script is not further executed.

catkin 02-13-2012 01:46 AM

Quote:

Originally Posted by jonaskellens (Post 4600505)
But I read all over the internet that the syntax $(command) is the correct way of executing a command.

It is the correct way to capture the output of a command when modified to my_variable=$(command 2>&1) (the 2>&1 captures the stderr output as well as the stdout).

The way to run a command is simply command

This makes sense when you think of a bash script being a automated command prompt session. At the command prompt, you run a command by typing it and pressing Enter.

catkin 02-13-2012 01:49 AM

Quote:

Originally Posted by jonaskellens (Post 4600680)
However, even with StartProg=$(/sbin/service prog start) I still get no output and the script is not further executed.

As long as the command terminates you should see the output of
Code:

echo $StartProg
echo "after"

Please post your latest script if you do not see that output.

jonaskellens 02-18-2012 04:58 AM

Thank you for your help. I notice that execution of the command hangs... I think it is related to the service that is being started. That's why I now execute another bash script which executes this command. This way my "main" bash script is further executed. It works well.

Another question :

suppose CheckNumber="[space][space][space]7"

I want to get the last 2 ciphers of this string. If there is only one cipher, I want to delete white spaces. I do the following :

Number=${CheckNumber:0:2} # get last 2 characters
${Number//[[:space:]]} # delete white spaces

if [[ "$Number"=="0" ]]; then
echo "number 0"
else
echo "number more than 0"
fi

I notice that the variable $Number is always empty.
So my if-then-else also fails.

See what I'm doing wrong ?

catkin 02-18-2012 05:04 AM

If the command does not terminate you could put it in the background by appending & to the command.

catkin 02-18-2012 05:09 AM

Quote:

Originally Posted by jonaskellens (Post 4605743)
suppose CheckNumber="[space][space][space]7"

I want to get the last 2 ciphers of this string. If there is only one cipher, I want to delete white spaces. I do the following :
Code:

Number=${CheckNumber:0:2} # get last 2 characters
${Number//[[:space:]]} # delete white spaces

if [[ "$Number"=="0" ]]; then
        echo "number 0"
else
        echo "number more than 0"
fi

I notice that the variable $Number is always empty.
So my if-then-else also fails.

See what I'm doing wrong ?

Add the command set -xv just before the problem section to better see what the script is doing.

Bash wants spaces either side of comparison operators such as == and you want the numeric comparison operator -eq, not the string comparison operator ==.

jonaskellens 02-18-2012 05:53 AM

Code:

CheckNumber="  7"
+ CheckNumber='  7'
echo $CheckNumber
+ echo 7
7
Number=${CheckNumber:0:2}
+ Number='  '
echo "  Number: $Number"
+ echo '  Number:  '
  Number: 
${Number//[[:space:]]}
echo "  Number: $Number"
+ echo '  Number:  '
  Number: 
if [[ "$Number"=="0" ]]; then
        echo "number 0"
else
        echo "number more than 0"
fi
+ [[ -n  ==0 ]]
+ echo 'number 0'
number 0


catkin 02-18-2012 06:06 AM

The comment does not match the code in ...
Code:

Number=${CheckNumber:0:2} # get last 2 characters
... the code gets the first two characters as the set -xv trace shows.

If you want to use echo to display the value of variables you must double quote them or bash will strip leading/training whitespace and convert all embedded whitespace sequences to a single space. It is also helpful to put markers at beginning and end so you can see any leading/training whitespace:
Code:

echo "Number: '$Number'"
The else echo in ...
Code:

if [[ "$Number"=="0" ]]; then
        echo "number 0"
else
        echo "number more than 0"
fi

... is wrong. The else case is triggered when $Number is not equal to the string 0 -- or would be if the == in the test expression had space either side of it so it was a comparison operator and not a component of the string "$Number"=="0" which is actually "==0" at run time as the set -xv trace shows.

jonaskellens 02-18-2012 06:40 AM

${CheckNumber: -2} does now what I want it to do...

Number=${Number/ /} removes white spaces...

However, still looking for a correct if-then-else

jonaskellens 02-18-2012 06:58 AM

The following is a good if-then-else :

if [[ $Number -eq 0 ]]; then

catkin 02-18-2012 11:31 AM

Quote:

Originally Posted by jonaskellens (Post 4605782)
Number=${Number/ /} removes white spaces

It removes spaces. Your previous version, ${Number//[[:space:]]}, removes whitespace. Whitespace is any of the characters space, tab and newline.

EDIT: actually ${Number/ /} removes only the first space. ${Number// /} removes all spaces and can be more simply given as ${Number// }. Here's a command prompt illustration:
Code:

c@CW8:~$ x=' a b c '
c@CW8:~$ echo "'${x/ /}'"
'a b c '
c@CW8:~$ echo "'${x// /}'"
'abc'
c@CW8:~$ echo "'${x// }'"
'abc'



All times are GMT -5. The time now is 10:38 AM.