How can I prompt the user inside a while read loop? [duplicate] - bash

This question already has answers here:
Read user input inside a loop
(6 answers)
How to read from user within while-loop read line?
(3 answers)
Closed 5 years ago.
For my purpose, I need to execute a shell command, achieve the output, and for each line ask user for prompt.
The problem is that on the read prompt, stdin buffer isn't empty
this is my code:
#!/bin/sh
git branch -a | sed 's/remotes\/origin\///g'
echo "############################"
git branch -a | sed 's/remotes\/origin\///g' | while read line
do
if [[ "$line" != *develop* ]] \
&& [[ "$line" != *master ]] \
&& [[ "$line" != *release/* ]] \
&& [[ "$line" != *hotfix* ]]
then
read -r -p "Do you want to delete branch $line <y/N>?" prompt
echo $prompt
fi
done
The line:
read -r -p "Do you want to delete branch $line <y/N>?" prompt
does not even display to video, and prompt variable show the result of line variable above.
How can I solve this problem?

Use a FD other than 0 (stdin), to leave the original stdin free for input from the user:
#!/usr/bin/env bash
# ^^^^- NOT /bin/sh; also, do not run with "sh scriptname"
while read -r line <&3; do
line=${line#remotes/origin/} # trim remotes/origin/ w/o needing sed
case $line in
*develop*|*master|*release/*|*hotfix*) continue ;;
*) read -r -p "Do you want to delete branch $line <y/N>?" prompt
echo "$prompt" ;;
esac
done 3< <(git branch -a)
Here, we're using FD 3 for output from git, such that FD 0 is still stdin, available to read from the user; and then redirecting <&3 on the explicit read where we want content from git.

Related

Why is bash swallowing characters

I have the following code in a bash script:
ssh_management
if [[ "$PROMPT_SSH" == "true" ]]; then
read -p "Generate and Install SSH keys? [y/n]" -n 1 -r
echo ""
if [[ $REPLY =~ ^[Yy]$ ]]; then
generate_container_ssh
install_ssh_keys
check_ssh_state
else
echo "Skipping SSH key install"
fi
fi
install_docker
But the script errors with:
Skipping container SSH key install
bash: line 102: nstall_docker: command not found
It appears that the read command is somehow swalling the first character on install_docker
Not sure why this is happening or how it fix it.
Seems something was messing up my STDIN.
read -p "Generate and Install SSH keys? [y/n]" -n 1 -r < /dev/tty
Fixes the problem.

Pseudo-input for Bash's "read" variable

I have a script listening for a user input like that.
read -p "Run? (y/[n]) " -n 1 -r
if [[ $REPLY =~ ^[Yy]$ ]]; then
[..]
fi
Is there a way (upon executing the script) to already send the value which
read is going to read and handle?
your_script.sh <<< "Y"
This also supports multiple read's
your_script.sh <<< "YNYYNNY"

read builtin doesn't work with pipe

I'd like to ask user a confirmation to read from stdin (Display output [Y/n]). It works Ok if some arguments were provided, or no arguments were provided but there was some input. However, if some data was piped to the script, there's no confirmation.
#!/bin/bash
output_file=$(mktemp)
cleanup() {
rm -f "$output_file"
}
trap cleanup 0 1 2 3 15
if [ $# -gt 0 ]; then
while [ $# -gt 0 ]; do
echo "$1" >> "$output_file"
shift
done
else
while read -r line; do
echo "$line" >> "$output_file"
done
fi
while true; do
read -p "Display output? [Y/n]" response
if [ -z "$response" ]; then
break
fi
case $response in
[Yy]*) break;;
[Nn]*) exit;;
esac
done
less "$output_file"
What prevent read -p to work? What should be done to provide consistent behavior?
The read command reads input from standard in. If you have standard in fed from a pipe then read looks for its data from the pipe, not from your terminal.
On most platforms you can work around this by redirecting the read command's input directly from the tty device, as in:
read -p "Display output? [Y/n]" response </dev/tty
If the script read everything from standard input, what is the read -p going to get? And it likely doesn't prompt if the input is not an 'interactive device' (aka terminal). Have you checked the Bash man page for read? It says:
-pprompt
Display prompt, without a trailing newline, before attempting to read any input. The prompt is displayed only if input is coming from a terminal.
When your input is from a pipe, it is not from a terminal.

Bash command runs only once in a while loop [duplicate]

This question already has answers here:
While loop stops reading after the first line in Bash
(5 answers)
Closed 6 years ago.
I am writing a Bash file to execute two PhantomJS tasks.
I have two tasks written in external JS files: task1.js & task2.js.
Here's my Bash script so far:
#!/bin/bash
url=$1
cd $(cd $(dirname ${BASH_SOURCE}); pwd -P)
dir=../temp
mkdir -p $dir
file=$dir/file.txt
phantomjs "taks1.js" $url > $file
while IFS="" read -r line || [[ -n $line ]]; do
dir=../build
file=$dir/$line.html
mkdir -p $(dirname $file)
phantomjs "task2.js" $url $line > $file
done < $file
For some unknown reason task2 is being run only once, then the script stops.
If I remove the PhantomJS command, the while loop runs normally until all lines are read from the file.
Maybe someone knows why is that?
Cheers.
Your loop is reading contents from stdin. If any other program you run consumes stdin, the loop will terminate.
Either fix any program that may be consuming stdin to read from /dev/null, or use a different FD for the loop.
The first approach looks like this:
phantomjs "task2.js" "$url" "$line" >"$file" </dev/null
The second looks like this (note the 3< on establishing the redirection, and the <&3 to read from that file descriptor):
while IFS="" read -r line <&3 || [[ -n $line ]]; do
dir=../build
file=$dir/$line.html
mkdir -p "$(dirname "$file")"
phantomjs "task2.js" "$url" "$line" >"$file"
done 3< $file
By the way, consider taking file out of the loop altogether, by having the loop read directly from the first phantomjs program's output:
while IFS="" read -r line <&3 || [[ -n $line ]]; do
dir=../build
file=$dir/$line.html
mkdir -p "$(dirname "$file")"
phantomjs "task2.js" "$url" "$line" >"$file"
done 3< <(phantomjs "task1.js" "$url")

Use read builtin command to read from parent stdin while in a subshell

I have script that is launching a subshell/background command to read input and then doing more work:
#!/bin/bash
(
while true; do
read -u 0 -r -e -p "test_rl> " line || break
echo "line: ${line}"
done
) &
sleep 3600 # more work
With the above I don't even get a prompt. If I exec 3>&0 prior to launching the subshell and then read from descriptor 3 (-u 3) then I at least get the prompt, but the read command still doesn't get any input that I type.
How do I get the read builtin to read correctly from the terminal (parent's stdin file descriptor)?
How do I get the read builtin to read correctly from the terminal
(parent's stdin file descriptor)?
You might want to try this (using the parent's filedescriptors):
#!/bin/bash
(
while true; do
read -u 0 -r -e -p "test_rl> " line || break
echo "line: ${line}"
done
)<&0 >&1 &
sleep 3600 # more work

Resources