script skipping user input in nested case statement
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
doneRunning 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
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
doneusually 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.
0Your usage of the "read" command doesn't seem to be quite right.
read -p "Do you wish to input data ?" ynThe -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