bash script while loop with read input from user [duplicate] - linux

This question already has answers here:
How to create a dynamic variable and assign value to it?
(2 answers)
Closed 5 years ago.
Wondering if there is an easy way to do what im attempting and the best way to go about something like this.
answer=y
while [ "$answer" = y ]
do
echo "type name of the file you wish to delete"
IFS= read -r file
echo "would you like to delete another file [y/n]?"
IFS= read -r answer
done
echo "Exiting Program"
exit 0
My questions here is when an input is entered it gets stored in file but I would like when the answer is y that it can then get stored to another variable like file1.
Im then left with variables containing all the filenames someone wishes to delete which I can echo back.
How can I use a loop in this to keep adding the input until someone types n
Thanks for the help.

I wouldn't use a realtime read loop to delete files. Too many things can go wrong. Rather, maybe take a file of input and check each.
But for a simplistic answer to your question -
typeset -l answer=y # force to lowercase
lst=/tmp/file.list.$$
while [[ y == "$answer" ]]
do
echo "type name of the file you wish to delete"
IFS= read -r file
if [[ -e "$file" ]]
then echo "$file" >> $lst
else echo "That file does not exist/is not accessible."
fi
echo "would you like to delete another file [y/n]?"
IFS= read -r answer
done
echo -e "Files to be deleted:\n===\n$(<$lst)"
echo -e "\n===\n Delete all listed files [y/n]?"
IFS= read -r answer
if [[ y == "$answer" ]]
then rm $(<$lst)
fi
rm $lst

Maybe this helps:
while :; do
read -s -n 1 answer
if [ $answer = "y" || $answer = "Y" ]; then <your code>
elif [ $answer = "n" || $answer = "N" ]; then echo; echo; break
elif [ $answer = "" ]; then continue # pressed: return key
fi
done
depending the shell you use, you might use: [[ ${answer} =~ (Y|y) ]]

Related

Bash script that allows one word as user input

Made a script that the user gives a "parameter" and it prints out if it is a file, directory or non of them. This is it :
#!/bin/bash
read parametros
for filename in *
do
if [ -f "$parametros" ];
then
echo "$parametros is a file"
elif [ -d "$parametros" ];
then
echo "$parametros is a directory"
else
echo " There is not such file or directory"
fi
exit
done
Altough i want the user to be allowed to give only one word as a parameter. How do i make this happen ? (For example if user press space after first word there would be an error message showing "wrong input")
#!/bin/bash
read parametros
if [[ "$parametros" = *[[:space:]]* ]]
then
echo "wrong input"
elif [[ -f "$parametros" ]]
then
echo "$parametros is a file"
elif [[ -d "$parametros" ]]
then
echo "$parametros is a directory"
else
echo " There is not such file or directory"
fi
See http://mywiki.wooledge.org/BashFAQ/031 for the difference between [...] and [[...]].
You have to use the $#. It gives the number of the parameters.
The code will be something like:
if [ "$#" -ne 1 ]; then
printf 'ERROR!\n'
exit 1
fi
First, I'm curious why you want to restrict to one word - a file or directory could have spaces in it, but maybe you are preventing that somehow in your context.
Here are a few ways you could approach it:
Validate the input after they enter it - check if it has any spaces, eg: if [[ "parametros" == *" " ]]; then...
Get one character at a time in a while loop, eg with: read -n1 char
Show an error if it's a space
Break the loop if it's 'enter'
Build up the overall string from the entered characters
1 is obviously much simpler, but maybe 2 is worth the effort for the instant feedback that you are hoping for?

User Input comparison with .txt

Writing a code that quizzes a user with questions from a file, compares the user_input with the answers in a .txt file. Can't seem to wrap my head around why it doesn't compare the answers and does not increment the variable by 1 for each correct answer. Might it be because the script doesn't read the answer.txt file?
#!/bin/bash
clear
questions=$1
answers=$2
correct=0
wrong=0
while read line #IFS = internal field Seperator
do
echo
echo $line
echo
echo "Your Answer:\c"
read user_answer </dev/tty #reads answer from terminal
if [ "$user_answer = $answers" ]; then
correct =$((correct + 1))
fi
done < $questions
echo
echo "Correct Answers: $correct "
echo "Wrong Answers: $wrong" ```
Assume that both the question and answer files have the same number of lines. The while loop will read one line from each file at each iteration, using separate file descriptors for each file. Standard input will be left alone, to allow the user to enter an answer.
clear
questions=$1
answers=$2
correct=0
wrong=0
while IFS= read -r q <&3 # Read from descriptor 3
IFS= read -r a <&4 # Read from descriptor 4
do
echo
echo "$q"
echo
echo "Your Answer:\c"
IFS= read -r user_answer
if [ "$user_answer" = "$a" ]; then
echo "Correct!"
correct=$((correct + 1))
else
echo "Wrong!"
wrong=$((wrong + 1))
fi
done 3< "$questions" 4< "$answers" # Use 3 for questions, 4 for answers
echo
echo "Correct Answers: $correct "
echo "Wrong Answers: $wrong"

How to add an unknown amount of numbers from user input in Linux shell script

I'm trying to add up all numbers inputted by a user, however there is no limit on how many numbers a user can input for the addition. How do I code this in linux shell script?
I have this so far:
firstNumber=0
secondNumber=0
number=0
echo Please enter two numbers to add up
read firstNumber
read secondNumber
echo Would you like to keep adding numbers? YES OR NO
read answer
if answer = YES
then
echo Please add another number
read number
echo $(($firstNumber +$secondNumber + $number))
fi
while answer = NO
do
echo $(($firstNumber + $secondNumber))
done
as #dash-o recommended, a simple entry sequence ended with ENTER is the most simple approach:
#!/usr/bin/env sh
sum=0
echo "Please enter integer numbers to add, or just RETURN to end."
while read -r number && [ -n "$number" ]; do
if [ "$number" -eq "$number" ] 2>/dev/null; then
sum=$((sum + number))
echo "Sum is: $sum"
else
echo "$number is not a valid integer. Try again..." >&2
fi
done
Or to allow multiple integers entry per line:
#!/usr/bin/env sh
# Save the shell's options state
shelloptions="$(set +o)"
# Disable globbing to prevent filename expansion in parameters
set -o noglob
sum=0
echo "Please enter integer numbers to add, or RETURN to end."
# Read lines until empty REPLY
while read -r && [ -n "$REPLY" ]; do
# Split $REPLY as parameters
# Globbing is turned-off so filenames will not mess with entries
# shellcheck disable=SC2086 # Explicitly intended word splitting
set -- $REPLY
# Iterate numbers from the parameters array
for number in "$#"; do
# If $number is a valid integer
if [ "$number" -eq "$number" ] 2>/dev/null; then
sum=$((sum + number))
else
echo "$number is not a valid integer." >&2
fi
done
echo "Sum is: $sum"
done
# Restore the shell's options state
eval "$shelloptions"

syntax checking for config files

I have a requirement to check the syntax of some config files.
The format of the config is as below:
[sect1]
sect1file1
sect1file2
[sect1_ends]
[sect2]
sect2file1
sect2file2
[sect2_ends]
My requirement is to check the for start of sect1 which is inside square brackets [sect1], then check that the files sect1file1 and sect1file2 exist, then check for the end of sect1 by reading sect1_ends inside square braces [sect1_ends]. Then repeat the same for sect2, and so on.
There is already a set of section names which are permitted. My objective is to check whether the section names are in the list, and whether the syntax is without any error.
I tried using
perl -lne 'print $1 while (/^\[(.*?)\]$/g)' <config filename>
but I'm not sure how to check and go through the file.
I am happy to see you have tried. Try again with this prototype:
while read -r line; do
if [ ${#line} -eq 0 ]; then
continue # ignore empty lines
fi
if [[ "${line}" = \[*\] ]]; then
echo "Line with [...]"
if [ -n "${inSection}" ]; then
if [ "${line}" = "${inSection/]/_ends]}" ]; then
echo "End of section"
unset inSection
else
echo "Invalid endtag ${line} while processing ${inSection}"
exit 1
fi
else
echo "Start of new section ${line}"
inSection="${line}"
fi
else
if [ -f "${line}" ]; then
echo "OK file ${line}"
else
echo "NOK file ${line}"
fi
fi
done < inputfile
Your solution looks good, but -n reads lines from standard input (STDIN). You need to feed your config file into STDIN to pass it to your script:
perl -lne 'print $1 while (/^\[(.*?)\]$/g)' <config.ini
Alternate option would be using -p.

If then elif then else statement in bash

then, elif, else statement that I have programmed in a bash script. I know that it works because I can run the same command in the terminal interface and see that it is doing what I want it to do. However when I run it in a script it seems to always jump to the else statement and not detect anything. Can anybody help explain why this is so? Here is my script code:
if [ -e "$1" ]
then
for line in `samtools view -H $1`
do
if [[ "$line" == *NCBI-Build-36\.1* ]]
then
echo "hg18"
break
elif [[ "$line" == *hg19* ]]
then
echo "hg19"
break
else
echo "Reference was not found, manual entry required: "
read ans
echo "$ans"
break
fi
done
else
echo -e "Usage: \e[1;32mreadRef.sh \e[1;36mbamfile.bam"
fi
No matter what file I plug in it always skips to the else and asks me for manual entry.
Here is the command I ran on terminal:
for line in `samtools view -H $bignormal`; do if [[ "$line" == *NCBI-Build-36\.1* ]]; then echo "YES - $line"; else echo "NO - $line"; fi; done
And the output is like this:
NO - #HD
NO - VN:1.0
NO - GO:none
NO - SO:coordinate
NO - #SQ
NO - SN:1
NO - LN:247249719
YES - AS:NCBI-Build-36.1
YES - UR:http://www.bcgsc.ca/downloads/genomes/9606/NCBI-Build-36.1/bwa_ind/genome/
NO - SP:Homo
NO - sapiens
.
.
.
Why is the script not detecting the string I am looking for, but it is in terminal?
EDIT:
I tried what Charles said, this is the output:
:+'[' -e /projects/rcorbettprj2/DLBCL/CNV/RG065/normal/A01440_8_lanes_dupsFlagged.bam ']'
::+samtools view -H /projects/rcorbettprj2/DLBCL/CNV/RG065/normal/A01440_8_lanes_dupsFlagged.bam
:+for line in '`samtools view -H $1`'
:+case "$line" in
:+echo 'Reference was not found, manual entry required: '
Reference was not found, manual entry required:
:+read ans
I think your code has a logic error nobody's spotted yet. I'm not sure, since you haven't told us what the script's supposed to be doing, but it looks to me like what you want is to ask for manual entry only if you don't find a match to either of your patterns anywhere in the output, but what you're actually doing is examining only the first word of output for a match. And from your sample output, the first word is "#HD", which doesn't match either pattern, so the script is doing exactly what I'd expect.
Now, assuming I'm right and that the point is to look for either pattern anywhere in the output, you can actually simplify things a bit. Mainly, you don't need the loop, you can just do a single comparison to look for the pattern in the entire output at once:
#!/bin/bash
if [ -e "$1" ]
then
output="$(samtools view -H "$1")"
if [[ "$output" == *NCBI-Build-36.1* ]]
then
echo "hg18"
elif [[ "$output" == *hg19* ]]
then
echo "hg19"
else
read -p "Reference was not found, manual entry required: " ans
echo "$ans"
fi
done
else
echo -e "Usage: \e[1;32mreadRef.sh \e[1;36mbamfile.bam"
fi

Resources