8

I'm creating a script to update my linux distribution if I need to wipe the HD or I need to install Linux on another machine. So this script basically install all the programs I usually need. At the beginning a have a "read" command that asks if I want to install all the packages automatically or not. If I choose not, for each program not found it should ask me I want it to be installed and I use this code

if [[ $installall == "yes" ]]; then
    echo " Installing $sciprog..."
    sudo apt-get install -y $sciprog >/dev/null
    {
        scitest=`dpkg -s $sciprog | grep Status`
    } 2>${HOME}/musthave.errorlog
    if [[ $scitest != "Status: install ok installed" ]]; then
        echo " I've encountered problems installing $sciprog that I can't resolve. "
        echo " Consider installing $sciprog manually. "
        {
            echo "=========="
            echo " $sciprog"
        } >>${HOME}/musthave.notinstalled
    else
        echo " $sciprog installed correctly!"
        {
            echo "=========="
            echo " $sciprog"
        } >>${HOME}/musthave.installed
    fi
else
    echo " Seems like $sciprog is not installed... Do you want to download it?"
    echo " Type 'y' for yes."

    read secondyn ### THIS IS THE GUILTY COMMAND ###

    if [[ $secondyn == "y" ]]; then
        echo " Installing $sciprog ..."
        sudo apt-get install -y $sciprog >/dev/null
        {
            checkinstall=`dpkg -s $sciprog | grep Status`
        } 2>>${HOME}/musthave.errorlog
        if [[ $checkinstall != "Status: install ok installed" ]]; then
            echo " I've encountered problems installing $sciprog that I can't resolve. "
            echo " Consider installing $sciprog manually. "
            {
                echo "=========="
                echo " $sciprog"
            } >>${HOME}/musthave.notinstalled
        else
            echo " $sciprog installed correctly!"
            {
                echo "=========="
                echo " $sciprog"
            } >>${HOME}/musthave.installed
        fi
    else
        echo " Skipping $sciprog ..."
        {
            echo "=========="
            echo " $sciprog"
        } >>${HOME}/musthave.notinstalled
    fi
### some more code which works as expected. All the code above is inside a 
### while...do...done loop which reads line by line the file at the end
done <${HOME}/file.list

But if I run the script, it skips the "read" command in the else clause and assumes it to be "n"...

I can't figure out why, there are other read function also inside if...then...else...fi loops and they work as expected...

Any ideas?

  • It's hard to tell because it looks like your indenting got mangled horribly in posting, but you seem to be missing a final `fi`. Also, the `read` works for me. – jw013 Aug 02 '11 at 11:59
  • Also, what is the shebang at the top of your script? `#!/bin/bash` or other? AND, just to be sure, you **are** running this from a command-line in a terminal session, yes? If you are crontabing it, the script will read a '' as the result and keep going. Good luck. – shellter Aug 02 '11 at 15:01
  • @jw013 well, maybe it has been cut while I copied/pasted it but the fis are correct, otherwise the script would raise an error –  Aug 02 '11 at 15:30
  • @shellter it's `#!/bin/bash` yes. And yes, I run the script from the command line using `./script.sh` –  Aug 02 '11 at 15:31
  • @Vieler : Forgot to ask, do you see the messages above the `read` but inside the `else`? (It seems like you know what you're doing, so sorry for asking what is probably too obvious a question) ; Good luck! – shellter Aug 02 '11 at 17:59
  • @shellter Don't worry, actually I'm not that good in bash scripting, it's rather new for me. Anyway, yes, the echo commands work fine and I see the strings printed on stdout. –  Aug 03 '11 at 09:12

3 Answers3

16

The relevant portions of the code are still not complete but based on the comments I'm going to guess that your while loop looks like

while read -r ... ; do 
    # do stuff ...

    # read user input
    read -r var

done < file

From this the problem is immediately apparent: the inner read is getting its input from the same place as the outer loop, namely stdin which has been redirected from file, and not the user. For a slightly more portable alternative that does not depend on kernel-level support for /dev/tty, just use a different file descriptor other than stdin for the while loop.

while read -r ... <&9; do
    # loop stuff

    # stdin still attached to the terminal untouched, 
    # so this reads from the terminal as expected
    read -r var 

done 9< file

Notice that this example uses fd 9 for the file, leaving fd 0 (stdin) alone. Take a look at the BashFAQ 089 for more details.

jw013
  • 1,718
  • 17
  • 22
  • 1
    Yes, that was the problem. Also I guess this solution is better for portability so thanks for putting me on the right track. –  Aug 03 '11 at 10:04
9

Try reading from the controlling terminal device:

read secondyn </dev/tty
jon
  • 91
  • 1
1
read secondyn < /proc/${PPID}/fd/0

That will look to the parent's input, which should still be stdin.

brightlancer
  • 2,059
  • 15
  • 7