Star Hype News.

Premium celebrity moments with standout appeal.

general

script skipping user input in nested case statement

By John Thompson

I am trying to create a nested case statement in which user input is expected (Y/N). However, the system never waits for the input and always goes to the third option, "Please answer yes or no". Can anyone tell me what I am missing?

Here is the case statement

#!/bin/bash
STATUS=status
find /etc/init.d/* -name '*' -print0 | while IFS= read -r -d '' FILE;
do
if [ "$FILE" != "." -o "$FILE" != ".." ]; then
OUTPUT=$($FILE $STATUS)
case "$OUTPUT" in *disabled* ) echo "Do you wish to start $FILE ?" read yn case $yn in [yY] | [yY][Ee][Ss] ) $FILE start ;; [nN] | [n|N][O|o] ) ;; * ) echo "Please answer yes or no.";; esac ;; * ) echo "App $FILE is running"
;;
esac
fi
done

Running under Ubuntu 14.04 LTS

Sample output

App /etc/init.d/reboot is running
App /etc/init.d/resolvconf is running
App /etc/init.d/rsync is running
App /etc/init.d/rsyslog is running
App /etc/init.d/samba is running
App /etc/init.d/samba-ad-dc is running
Do you wish to start /etc/init.d/saned ?
Please answer yes or no.
2

3 Answers

You're piping find output to the while loop. The inner read command is reading a line from find's output, not from stdin.

You can restructure like this: send the find output to the while loop on a different file descriptor. This leaves stdin free for the inner read.

while IFS= read -u3 -r -d '' FILE; do if [ "$FILE" != "." -o "$FILE" != ".." ]; then OUTPUT=$($FILE $STATUS) case "$OUTPUT" in *disabled* ) read -p "Do you wish to start $FILE ?" yn case $yn in [yY] | [yY][Ee][Ss] ) $FILE start ;; [nN] | [nN][Oo] ) ;; * ) echo "Please answer yes or no.";; esac ;; * ) echo "App $FILE is running" ;; esac fi
done 3< <(find /etc/init.d/* -name '*' -print0)

This uses a process substitution, instead of a pipe, to read from find

0

The context this time provides the answer. You are piping the output of find into the entire while loop, and that includes your inner read as well... meaning, your "read yn" will also read from the very same output that "find" provides, as opposed to from your keyboard.

I also dislike your general handling of looping over files. A simple:

for file in /etc/init.d/*; do echo Processing $file
done

usually works well nowadays, even for larger amounts of files.

If you really must use find, you could perhaps wrap your handler inside another script, and call it for each file with:

find /etc/init.d -type f -perm +111 -exec myhandlerscript.sh {} \;

This will find all files with executable permissions, and call myhandlerscript.sh for each one with the name as argument. Inside the script, the file name will appear inside the $1 special variable.

If it really must be in the same file, wrap the code inside a function, export it with "export -f myfunction", and use "-exec bash -c 'myfunction "$0"' {} \;" as a parameter to find.

0

Your usage of the "read" command doesn't seem to be quite right.

read -p "Do you wish to input data ?" yn

The -p switch expects a string right next to it, which will be used as the Prompt. Thus it thought that "yn" was something to display, rather than the variable to store the answer in.

4

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy