LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Bash help (https://www.linuxquestions.org/questions/linux-newbie-8/bash-help-4175447215/)

druadunc91 01-25-2013 01:56 PM

Bash help
 
Hey there,

I'm new here and currently taking Bash Programming in college. I'm having a little problem right now with my code

i'm trying to have my program output the date/time whenever a user inputs the word "time" when my program prompts them to enter something

so far this is what the code looks like and I'm getting an integer expression expected


Quote:

clear
echo; echo; echo
echo -n Enter something: ' '
read x
if [ "$x" -eq "time"]
then
echo date
fi
what am I forgetting?

jpollard 01-25-2013 02:13 PM

-eq is a numeric comparison.

You want either == (or = when used in an expression), also suggest space after the closing " on "time".

Run down the bash manpage to "Conditional Expressions"

druadunc91 01-25-2013 02:15 PM

that worked, thanks! I'll be back for more help soon, probably

question: with if statements, if you have an if inside an if, do you need a fi at the end of the inner if statement

example:

Quote:

if [blah blah]
then
echo `blah`
if [blah1 blah1]
then
echo `blah1`
fi
fi

YankeePride13 01-25-2013 02:28 PM

Quote:

Originally Posted by druadunc91 (Post 4877571)
that worked, thanks! I'll be back for more help soon, probably

question: with if statements, if you have an if inside an if, do you need a fi at the end of the inner if statement

example:

yes.

druadunc91 01-25-2013 03:35 PM

Ok,

so more problems.

Here's my code:
Quote:

clear
echo;echo;echo
echo -n Enter something: ' '
read x
if [ "$x" = "time"]
then
echo `date`
elif [ "$x" = "Directory"
then
echo `pwd`
fi
else [ "$x" = "Who"]
then
echo `who`
fi
When I enter "Directory" as my input, it tells me where I am at in my assignment. So the the output for me looks like this:
Quote:

/home/druadunc/csc490/bin
but there is more. after that it shows:
Quote:

./task02: line 12: syntax error near unexpected token 'else'
so im getting the correct output, but im getting an error message for my last if that I have. the statement bolded is the one with the error message

jpollard 01-25-2013 03:41 PM

And the question is?

Habitual 01-25-2013 04:05 PM

Quote:

Here's my code:...
doesn't
Code:

elif [ "$x" = "Directory"
need a closing "]"?, so
Code:

elif [ "$x" = "Directory" ]
?

2 of the 3 braces need spaces before the closing right bracket.
time" ] and who" ] NOT
time"] or who"]

http://tldp.org/LDP/abs/html/testcon...ml#DBLBRACKETS

druadunc91 01-25-2013 04:06 PM

Quote:

Originally Posted by Habitual (Post 4877640)
doesn't
Code:

elif [ "$x" = "Directory"
need a closing "]"?, so
Code:

elif [ "$x" = "Directory" ]
?

sorry, i forgot to type then in the post...i have it in my coding

druuna 01-25-2013 04:09 PM

Quote:

Originally Posted by druadunc91 (Post 4877617)
Code:

clear
echo;echo;echo
echo -n Enter something: ' '
read x
if [ "$x" == "time" ]  # you need == and not = / missing space between " and ]
then
echo `date`
elif [ "$x" == "Directory" ]  # == -> = / missing square bracket
then
echo `pwd`
# if            # you need to use elif instead of if  else
#else

elif [ "$x" == "Who" ]  # == -> = / also needs an extra space.
then
echo `who`
fi


And those are to make the code work.

You might want to have a look at these:

Bash resources:

druadunc91 01-25-2013 04:10 PM

thanks for the help and info druuna!

on the who command, how do you get each user to appear on their own line so its not all mashed up?

suicidaleggroll 01-25-2013 04:27 PM

Quote:

Originally Posted by druadunc91 (Post 4877643)
thanks for the help and info druuna!

on the who command, how do you get each user to appear on their own line so its not all mashed up?

You don't need to use echo for any of those commands, as that's what they'll do anyway. Just run the command, eg:
Code:

elif [ "$x" == "Who" ]
then
  who
fi

Same goes for date and pwd. You use the back ticks or $() when you want to execute something and pass the output into something else, such as a variable for parsing later on. Passing it into echo is rather pointless, as that's what the command is going to do anyway (plus echo will jumble up the line ends).

You may also want to start indenting your if blocks, it makes larger codes infinitely easier to read.

druadunc91 01-26-2013 02:08 PM

added another elif statement, because my assignment seems to contain a lot of them. Anyways, all my scripts are working except for the last elif statement.

This is the error I get when I execute the script using the "trigger" work if you will.

Quote:

line 20: syntax error near unexpected token `elif'
line 20: elif [ "$x" == "Quit" ]'
Thats the error, section of code it goes to

Quote:

elif [ "$x" == "Quit' ]
then
echo Something
so, whats wrong with the script? I even tried changing echo Something to just `exit` to see if it would work, and it doesn't

druuna 01-26-2013 02:24 PM

Quote:

Originally Posted by druadunc91 (Post 4878113)
[code]elif [ "$x" == "Quit' ]
then
echo Something

You can't mix double and single quotes. A set of either has their own behavioural purpose (in short: one does allow expanding (""), the other doesn't ('').

druadunc91 01-26-2013 02:28 PM

That was my bad on typing here. My script has "". Still have same error

druuna 01-26-2013 02:30 PM

Please post the complete script, or at least the complete if-then-elif-fi part that doesn't work. Also post the exact error it throws.

druadunc91 01-26-2013 02:33 PM

Quote:

clear
echo;echo;echo
echo -n Enter something:' '
read x


if [ "$x" == "time" ]
then
`date`
elif [ "$x" == "Directory" ]
then
`pwd`
elif [ "$x" == "Who" ]
then
`who`
elif [ "$x" -le "9" ]
then
echo You entered a single digit number
else
echo You entered a number
elif [ "$x" == "Quit" ]
then
echo Something

fi
the bolded part is the part with the error

druuna 01-26-2013 02:40 PM

Quote:

Originally Posted by druadunc91 (Post 4878127)
Code:

if [ "$x" == "time" ]
then
 `date`
elif [ "$x" == "Directory" ]
then
 `pwd`
elif [ "$x" == "Who" ]
then
 `who`
elif [ "$x" -le "9" ]
then
 echo You entered a single digit number
else  # else needs to be last in the chain (if then elif then elif then else fi)
 echo You entered a number
elif [ "$x" == "Quit" ]  # see previous comment.
 then
 echo Something
fi


Have a look here: (BGFB) 7.2.1. if/then/else constructs

David the H. 01-27-2013 03:23 PM

Please use ***[code][/code]*** tags around your code and data, to preserve the original formatting and to improve readability. Do not use quote tags, bolding, colors, "start/end" lines, or other creative techniques.

1) When using bash or ksh, it's recommended to use [[..]] for string/file tests, and ((..)) for numerical tests. Avoid using the old [..] test unless you specifically need POSIX-style portability.

http://mywiki.wooledge.org/BashFAQ/031
http://mywiki.wooledge.org/ArithmeticExpression

2) When doing simple pattern matching on a variable string, a case statement is generally better to use. Unfortunately you can't do arithmetic comparisons in them (not directly, at least), but you can usually include a separate if statement either as a sub-command or as a separate one before or after it.

3) Finally, the shell has built-in variables for $PWD, $HOME, $USER and several others, so there's often no need for the external commands. See the bash man page.

Code:

clear
echo;echo;echo
echo -n Enter something:' '
read x

case ${x,,} in                #the "${var,,}" pattern forces the expansion to lowercase
                        #simplifying the pattern matching
    quit)
        echo "goodbye"
        quit
    ;;
    time)
        date
    ;;
    directory)
        echo "$PWD"
    ;;
    who)
        echo "$USER"
    ;;
    *[^0-9]*)                #the string contain non-digit characters
        echo "you entered an unknown text string"
    ;;
    [0-9]*)
        if (( $x <= 9 )); then
            echo "You entered a single digit number"
        else
            echo "You entered a multi-digit number"
        fi
    ;;

esac


druadunc91 01-27-2013 04:13 PM

David,

thanks for the help. The reason I am using [] is because that is how my professor is teaching us right now. The help though is much appreciated and if I have more questions, I will keep posting.

Thanks for all the help so far everyone!

chrism01 01-28-2013 07:22 PM

Do read the links given to you and please indent your code as shown above, its much easier to read that way.
Also, you can debug your code by using
Code:

set -xv
at the top

druadunc91 01-28-2013 09:07 PM

Code:

clear
echo;echo;echo
echo -n Enter something:' '
read x

        if [ "$x" == "Directory" ]
        then
        pwd
                elif [ "$x" == "Date" ]
                then
                date
                        elif [ "$x" == "Who" ]
                        then
                        who
                                elif [ ${#x} -gt 20 ]
                                then
                                echo "Stop over achieving, stick with less than 20 characters"
                                        elif [ "$x" == "Time" ]
                                        then
                                        date +%H:%M
                                                elif [ "$x" == "Quit" ]
                                                then

its not the finished code...i could have sworn I saved it last time i edited it. well, i'll fix it later...anyways, everything here works

chrism01 01-29-2013 01:38 AM

As above, prefer [[ ]] to [ ] http://tldp.org/LDP/abs/html/testcon...ml#DBLBRACKETS

David the H. 01-31-2013 12:55 PM

Re post #21, That's not the way to properly indent your code. The idea is that all commands that occur at the same level of execution line up at the same level of indentation.

if, elif, else, and fi are all part of the same complex command enclosure, and so should line up, with the sub-commands that it executes under those conditions indented an extra level.

In addition, many people prefer to put the then keyword on the same line as the if, since it's not an independent command, but paired with the previous keyword to bracket the test commands. It's how the shell knows where the test ends and the subcommands start. Putting them on the same line helps keep this visually clear and separate from the sub-commands (this can be relaxed if the test commands themselves occupy multiple lines).

This suggestion also applies to the do keyword in for/while loops.

Pay attention to vertical spacing too, which helps to visually define blocks that go together.

And finally, get into the habit now of commenting your code clearly as you're writing. You'll be very thankful for them when you start reviewing old scripts you wrote and start wondering what the heck you were thinking when you wrote it!

See here for more on good styling practice: Scripting With Style

Code:

clear

echo;echo;echo
echo -n Enter something:' '

read x

if [ "$x" == "Directory" ]; then
    pwd
elif [ "$x" == "Date" ]; then
    date
elif [ "$x" == "Who" ]; then
    who
elif [ ${#x} -gt 20 ]; then
    echo "Stop over achieving, stick with less than 20 characters"
elif [ "$x" == "Time" ]; then
    date +%H:%M
else
    if [ .... ]; then
        acommand
    else
        bcommand
    fi
fi

I fleshed it out at the end with an example of a sub-test to further illustrate proper nesting.

As I said before, a case statement would still be much better here, however, and the double-bracket tests.

druadunc91 01-31-2013 01:28 PM

Code:

clear
echo;echo;echo
echo -n Enter something:' '
read x

if [ "$x" == "Directory" ]
then
pwd

elif [ "$x" == "Date" ]
then
date

elif [ "$x" == "Who" ]
then
who

elif [ ${#x} -gt 20 ]
then
echo "Stop over achieving, stick with less than 20 characters"

elif [ "$x" == "Time" ]
then
hour="$(date +%H)"
        if [ "$hour" -ge "7" ] && [ "$hour" -le "12" ]
        then
        echo Morning
        elif [ "$hour" -ge "12" ] && [ "$hour" -le "17" ]
        then
        echo Afternoon
        elif [ "$hour" -ge "17" ] && [ "$hour" -le "20" ]
        then
        echo Evening
        elif [ "$hour" -ge "21" ] || [ "$hour" -le "4" ] && [ "$hour" -ge "0" ]
        then
        echo Night
        elif [ "$hour" -ge "4" ] && [ "$hour" -le "7" ]
        then
        echo

        fi

elif [ "$x" == "Quit" ]
then
echo "Bitch"

elif [ "$x" == "Quit" ]
then
echo "Bitch"

elif [[ $x =~ ^-?[0-9]+$ ]]
then
        if [ $x -ge 0 ] && [ $x -le 9 ] && [ ${#x} -eq "1" ]
        then
        echo "You entered a single digit  number"
        else
        echo "You have entered a number"
        fi
else
echo "$x"

fi

Here is the finished product. Everything worked the way it should and now, for my next assignment, I do exactly what I did here, but with case statements and not if statements

chrism01 01-31-2013 05:32 PM

As per David the H.'s example, you should indent all cmds between then .. elif, not just other 'if' blocks.
Same for else .. fi.

druadunc91 02-04-2013 04:53 PM

im back again. Some more help would be appreciated

For this next assignment, I'm taking my finished code and instead of using if's and elif's, I'm using case statements to make the program do exactly as my last one.

this is what I have

Code:

clear
echo;echo;echo
echo -n Enter something here: " "
read x

case "$x" in
        Directory)
                pwd
                ;;

        Date)
                date
                ;;
        Who)
                who
                ;;

esac

right now, i'm trying to get the program to tell the user if they entered more than 20 characters that it is too many.

this is what I tried

Code:

clear
echo;echo;echo
echo -n Enter something here: " "
read x

case "$x" in
        Directory)
                pwd
                ;;

        Date)
                date
                ;;
        Who)
                who
                ;;
        ${#x} -gt 20)
                echo "Over achiever!!!"
                ;;

esac

as with what i did before where I had [ ] around that last statement with the if's and elif's, do I need the brackets around the that line or what is wrong with it to say they entered more than 20 characters?

druuna 02-05-2013 01:32 AM

@druadunc91: To my knowledge the case statements expects a pattern to compare to and not a true/false expression.

Here is one way to edit your code to do what you require:
Code:

# replace the following

        ${#x} -gt 20)
                echo "Over achiever!!!"
                ;;

# with


        * )
                if [ ${#x} -gt 20 ]
                then
                  echo "Over achiever!!!"
                fi
                ;;

There are probably other ways, this came to mind first.

Also have a look here: ABSG - 11.4. Testing and Branching

druadunc91 02-05-2013 01:39 AM

Is there a way to do that expression without the if statement? This assignment is using just case statements

druuna 02-05-2013 01:59 AM

Quote:

Originally Posted by druadunc91 (Post 4884613)
Is there a way to do that expression without the if statement? This assignment is using just case statements

Have a look at this:
Code:

        * )
                [ ${#x} -gt 20 ] && echo "Over achiever!!!"
                ;;


David the H. 02-09-2013 08:21 AM

As mentioned before, a case statement takes the input string and compares it to a list of globbing patterns. The first pattern that matches in the list has its commands executed. Each potential match is equivalent to a "[[ $var == *pattern* ]]" test.

The only way you could directly use a pattern match to calculate "more than/less than" would be something like this:
Code:

case $text in

    ?|??|???|????) echo "Contains less than 5 characters" ;;
    ?????????????????????*) echo "Contains more than 20 characters" ;;
    *) echo "Contains 5-20 characters" ;;

esac

You have to match an exact number of characters and use logical thinking to output the answers you want.

An easier technique may be to match the length of the string directly, within a range of numbers:

Code:

case ${#text} in

    [0-9]) echo "0-9 characters" ;;
    1[0-9]) echo "10-19 characters" ;;
    2[0-9]) echo "20-29 characters" ;;
        *) echo "30 or more characters" ;;
 
esac

Note finally that bash has extended globbing, which can give you even more matching flexibility.


In any case, druuna's example is certainly the way to go here. greater than/less than style matches really need bracket tests. But here again I would use an arithmetic evaluation instead.

Code:

(( ${#var} > 20 )) && echo "Contains more than 20 characters" ))

PS: your code is looking better. Keep up the good work!

druadunc91 02-11-2013 10:39 AM

hey guys, im back again with more questions and help

here is my code:

Code:

clear
echo;echo;echo
echo -n Enter something here: " "
read x
hour="$(date +%H)"
case "$x" in
        "Directory")
                pwd
                ;;
        "Date")
                date
                ;;
        "Who")
                who
                ;;
        #"Time")
                case "$hour" in
                        [ "$hour" -ge "7" ] && [ "$hour" -le "12" ])
                              echo "Morning"
                              ;;
                        [ "$hour" -ge "12" ] && [ "$hour -le "17" ])
                              echo "Afternoon"
                              ;;
                        [ hour -ge "17" ] && [ "$hour" -le "20" ])
                              echo "Evening"
                              ;;
              esac
              ;;
        "Quit")
                echo "Bitch"
                ;;
        *)
                [ ${#x} -gt 20 ] && echo "Over achiever!!!"
                ;;
        #*)
        #      [ $x =~ ^-?[0-9]+$ ] && echo "You entered a number."
        #      ;;

esac

for the most part, it works...the only part, or I should say, parts, that doesn't work are the lines that are commented out. what do I do to fix these and with your answer, could you also give an explanation as to what you did?

Thanks again

EDIT: I took the %M out to look for just the hour and I'm still getting an error at line 18 and this is what the error says. Explanation of what is wrong would be greatly appreciated, i've encountered this error so many times and can seem to never find the problem

Quote:

Enter something here: Time
./task03: line 18: syntax error near unexpected token `"$hour"'
./task03: line 18: ` [ "$hour" -ge "7" ] && [ "$hour" -le "12" ])'

jpollard 02-11-2013 10:48 AM

Using "date +%H%M" to determine the hour is not going to work - you are running both hour and minute into a single string. So the minimum value you get will be "100" (no minutes past 1AM). What you likely want is just %H (hours).

druadunc91 02-11-2013 02:23 PM

so just by taking out the %M it should fix at least that one part since i'm just looking for the time between hours to determine if it is either morning, afternoon, or evening?

jpollard 02-11-2013 02:28 PM

That should do it.

druadunc91 02-11-2013 03:34 PM

i tried that and it didn't work...you can look at my previous post with the code in it. i added the error i'm getting from the code and bolded the line in which the error occurred. also, when i uncomment out the code that I'm having problems with, it causes the rest of my commands to not work when I test my program. And the error I'm getting is the same one on line 18 whether I type in Date to run the date command or Who for the who command

Snark1994 02-11-2013 03:39 PM

You can't use "case" with an 'if'-like structure: you used it correctly the first time (when you matched against e.g. "Directory", "Date") but for the second one you'll need to use if/elif/else instead.

druadunc91 02-11-2013 03:42 PM

Quote:

Originally Posted by Snark1994 (Post 4889400)
You can't use "case" with an 'if'-like structure: you used it correctly the first time (when you matched against e.g. "Directory", "Date") but for the second one you'll need to use if/elif/else instead.

that would be easier, but my instructor for this assignment wants us to specifically use case statements and nothing else. I understand that what I have for "Time" is the pattern for the case statement, but how do I get it to recognize the pattern and match the time with the corresponding time of day, such as if it is 7:01am, using military time since %H keeps it as a 24hr clock, to say morning?

Snark1994 02-11-2013 03:50 PM

You could pattern-match, I guess:

Code:

case "$hour" in
    0*)
        echo "Morning"
        ;;
    1[7-9])
        echo "Evening"
        ;;
    1*)
        echo "Afternoon"
        ;;
esac

(not tested, but hopefully should work)

EDIT: Just seen that you use less than or equals, not less than - but seeing as this is a class assignment I'm sure you can figure out how to extend the examples I gave ;)

druadunc91 02-11-2013 03:57 PM

Snark, thanks for the example. Now a question or two concerning your example. what does 1[7-9] mean? 7-9 is the pattern that the code is looking for and if it finds it, it would output evening and same thing for morning and afternoon? also, with your 1*) could I do 1[12-17] for afternoon, sticking with the military time that %H does?

Snark1994 02-11-2013 04:04 PM

Look at, say http://tldp.org/LDP/Bash-Beginners-G...ect_07_03.html.

1[7-9] should match 17, 18 and 19. 1* should match anything beginning with a '1' (which is why it is placed after 1[7-9]), but you could do 1[2-7] instead, yes (1[12-17] won't work).

druadunc91 02-11-2013 05:54 PM

thanks for the help, its starting to click with me.

more questions. if there is no command line arguments, how would you get the program to output a specified command. example: you press return without typing anything in and the output is, say, the command who. how would you do that without getting too complex

Snark1994 02-12-2013 06:16 AM

If I understand you correctly, match for an empty string and run

Code:

echo $(who)

jpollard 02-12-2013 08:41 AM

Do the same match, but drop the echo... Just use the who command directly.

The only time the $(...) syntax is useful is if you are putting the result into a variable.

Snark1994 02-13-2013 02:52 AM

Quote:

Originally Posted by jpollard (Post 4889869)
Do the same match, but drop the echo... Just use the who command directly.

The only time the $(...) syntax is useful is if you are putting the result into a variable.

Ah thanks, never realised that worked !

druadunc91 02-14-2013 12:56 PM

thanks for all the help guys. more questions


here is my code. it all works, but im having a problem with one part.

Code:

clear
echo;echo;echo
echo -n Enter something here: " "
read x
a="$(date +%H)"
case "$x" in
        [0-9]*)
                case "$x" in
                        [0-9])
                                echo "You entered a single digit number"
                        ;;
                        [0-9]*[a-z]*)
                                echo "$x"
                        ;;
                        [0-9]*[A-Z]*)
                                echo "$x"
                        ;;
                        [0-9]*)
                                echo "Big number!!!"
                        ;;
                esac
        ;;
        "Directory")
                pwd
                ;;
        "Date")
                date
                ;;
        "Who")
                who
                ;;
        "Time")
                case "$a" in
                        [0700-1159])
                                echo "Morning"
                                ;;
                        [1200-1700])
                                echo "Afternoon"
                                ;;
                        [2100-0400])
                                echo "Evening"
                                ;;
                        [0400-0700])
                                echo
                                ;;
                esac
        "Quit")
                echo "Bitch"
                ;;
            *)
                [ ${#x} -gt 20 ] && echo "Over achiever!!!"
                ;;
esac

the part that im having problems with is my Time pattern. when i execute the program and type in "Time", it doesn't output anything. It should output, corresponding with the time, morning, afternoon, evening, or nothing if its between 4am and 7am. i know its falling through somewhere around that area, but I cant seem to find where its falling through. I'm not getting any errors, and everything else outputs as it should. just not that time part

EDIT: I have it as %H for military time so I reflected that within the nested case statement

jpollard 02-14-2013 01:34 PM

%H provides 24 hour time, but as a two digit number (01 to 24), rather than a 4 digit number.

druadunc91 02-14-2013 06:47 PM

So just change my time values to 2 digits instead of the 4?

suicidaleggroll 02-14-2013 08:23 PM

Quote:

Originally Posted by druadunc91 (Post 4891885)
So just change my time values to 2 digits instead of the 4?

Why don't you test it and see what happens? The nice thing about shell programming is you can test individual commands from the command line to see if they behave the way you expect. Had you run your "date +%H" command and looked at the output, even once, you would have seen that it spits out a 2 digit hour and your case statement would fail. 75% of learning a programming language is trying things to see if and how they work, and changing your syntax to see what effect it has. Coding something up blindly and then asking people to fix it when it doesn't do what you want it to do doesn't help anybody learn anything.

druadunc91 02-25-2013 04:30 PM

can someone explain grep for me? i read about it and still dont really understand it.

also, this is some of my professor's code for the assignment

Code:

echo -e "$1\n$2\n$3\n$4\n$5" | sort | grep -v "^$"
what is the purpose of n$2, so on so forth and the grep code at the end?

jpollard 02-25-2013 05:15 PM

Have you tried doing each part of the command?
Have you tried reading the manpage on "echo"?
How about reading the manpage on "bash"?

We aren't here to do your homework.


All times are GMT -5. The time now is 11:22 AM.