bash to search file based on user input and create new file - bash
In the below bash a file is downloaded when the program is opened and then that file is searched based on user input and the result is written to a new file. As of now the file downloads and the user is prompted for the input, but after it is entered nothing happens.
For example, the bash is opened and the download.txt is downloaded, the user then enters the id (NA04520). The id is used to search download.txt and the line is written to match.txt. The code runs but no output result. Eventually, I will search for specific text in the line that id was found in, but I figured getting the search based on user input was a good start. Thank you :).
#!/bin/bash
cd 'C:\Users\cmccabe\Desktop\wget'
wget -O getCSV.txt http://xxx.xx.xxx.xxx/data/getCSV.csv --progress=bar:force 2>&1 | tail -f -n +6
{
printf "\n\n"
printf "What is the id of the NGS patient: "; read id
[ -z "$id" ] && printf "\n No ID supplied. Leaving match function." && sleep 2 && return
[ "$id" = "end" ] && printf "\n Leaving match function." && sleep 2 && return
}
input=$id
while read -r line
do
case $line in
*$id*)
echo $line " yes" >> bashgrep.txt
;;
*)
echo "no"
;;
esac
done
Contents of download.txt
Report,Status,Flows,Library,TF Name,Q10 Mean,Q17 Mean,System SNR,50Q10 Reads,50Q17 Reads,Keypass Reads,TF Key Peak Counts,Total_Num_Reads,Library_50Q10_Reads,Library_100Q10_Reads,Library_200Q10_Reads,Library_Mean_Q10_Length,Library_Q10_Coverage,Library_Q10_Longest_Alignment,Library_Q10_Mapped Bases,Library_Q10_Alignments,Library_50Q17_Reads,Library_100Q17_Reads,Library_200Q17_Reads,Library_Mean_Q17_Length,Library_Q17_Coverage,Library_Q17_Longest_Alignment,Library_Q17_Mapped Bases,Library_Q17_Alignments,Library_50Q20_Reads,Library_100Q20_Reads,Library_200Q20_Reads,Library_Mean_Q20_Length,Library_Q20_Coverage,Library_Q20_Longest_Alignment,Library_Q20_Mapped Bases,Library_Q20_Alignments,Library_Key_Peak_Counts,Library_50Q47_Reads,Library_100Q47_Reads,Library_200Q47_Reads,Library_Mean_Q47_Length,Library_Q47_Coverage,Library_Q47_Longest_Alignment,Library_Q47_Mapped Bases,Library_Q47_Alignments,Library_CF,Library_IE,Library_DR,Library_SNR,Raw Accuracy,Sample,Notes,Run Name,PGM Name,Run Date,Run Directory,Num_Washouts,Num_Dud_Washouts,Num_Washout_Ambiguous,Num_Washout_Live,Num_Washout_Test_Fragment,Num_Washout_Library,Library_Pass_Basecalling,Library_pass_Cafie,Number_Ambiguous,Nubmer_Live,Number_Dud,Number_TF,Number_Lib,Number_Bead,Library_Live,Library_Keypass,TF_Live,TF_Keypass,Keypass_All_Beads,P,s
Auto_user_MOL-95-Epilepsy70_125,Completed,500,hg19,TF_A,93.0,90.0,27.4077550007,27969.0,27031.0,28647.0,93.0,5046334,4861480,4439577,2307648,179,0.0,343,885197150,4942977,4689944,4272916,2213442,177,0.0,341,850800392,4796942,4465846,4082874,2050257,171,0.0,341,804445593,4698861,81.0,4073847,3251302,1186042,143,0.0,319,651683806,4541746,0.515698455274,0.728147709742,0.00734527275199,21.2101955615,99.4,NA04520,NA04520,R_2014_01_14_16_21_42_user_MOL-95-Epilepsy70,MolecularGenetics,2014-01-14 22:21:42+00:00,/results/MolecularGenetics/R_2014_01_14_16_21_42_user_MOL-95-Epilepsy70,0,0,0,0,0,0,0,0,0,9332288,14179,31491,9300797,9346467,0,0,9332288,0,0,"{""variantCaller"": {""hotspots"": {}, ""barcoded"": ""false"", ""Target Regions"": ""Epilepsy70"", ""Trim Reads"": true, ""Target Loci"": ""Not using"", ""variants"": {""no_call"": 0, ""homo_snps"": 50, ""het_snps"": 104, ""other"": 0, ""variants"": 163, ""het_indels"": 3, ""homo_indels"": 6}, ""Configuration"": ""Germ Line - Low Stringency"", ""Aligned Reads"": ""R_2014_01_14_16_21_42_user_MOL-95-Epilepsy70"", ""Library Type"": ""AmpliSeq""}}","{""FastqCreator"": {}}","{""coverageAnalysis"": {""Bases in target regions"": ""268545"", ""Amplicons with at least 1 read"": ""99.80%"", ""barcoded"": ""false"", ""Target base coverage at 100x"": ""97.72%"", ""Amplicons with at least 500 reads"": ""95.42%"", ""Total assigned amplicon reads"": ""4879939"", ""Reference (File)"": ""hg19"", ""Total aligned base reads"": ""884883559"", ""Target base coverage at 20x"": ""98.82%"", ""Number of amplicons"": ""1507"", ""Target bases with no strand bias"": ""84.70%"", ""Percent reads on target"": ""97.44%"", ""Amplicons with at least 100 reads"": ""98.08%"", ""Average base coverage depth"": ""3149"", ""Average reads per amplicon"": ""3238"", ""Using"": ""All Mapped Reads"", ""Amplicons reading end-to-end"": ""80.76%"", ""Non-duplicate"": """", ""Uniquely mapped"": ""No"", ""Targeted Regions"": ""Epilepsy70"", ""Uniformity of base coverage"": ""93.35%"", ""Targetted regions"": ""/results/uploads/BED/42/hg19/merged/plain/Epilepsy70.bed"", ""Target padding"": ""0"", ""Amplicons with at least 20 reads"": ""99.14%"", ""Number of mapped reads"": ""5007953"", ""Percent assigned amplicon reads"": ""97.44%"", ""Amplicons
Change the while loop to:
while IFS= read -r line
do
case "$line" in
*$id*)
echo "$line" >> bashgrep.txt
echo "yes"
#Assumed you want only $line to go to the file and print yes to stdout
;;
*)
echo "no"
;;
esac
done <download.txt
#change it to the name of the file downloaded.
#Your posted code seems to download getCSV.txt
Related
Bash Variable Not Being Assigned
I have this bash script, that gets an input from the user, and returns a phonetic transcription of the word, even if no transcription is available. However, the variable results isn't being assigned as a blank line is being printed instead of the value inside. I have tried putting the commands into a different script, and that also produced blank lines, and doubled checked that there was no space between results and = Code: #!/usr/bin/env bash #check if user entered a word to translate to ipa #if a word was not entered prompt the user to enter a word #else set the word passed as an argument to the variable current if [ -z "$1" ] then echo "You did not enter a word for translation, Please enter one now: " read current else current=$1 fi #confirm to user the word they entered echo "The word you chose for translation: $current" #format the word into '< w o r d >' onmt_word=$(python ONMT_DATA_FORMAT.py "$current") #write over current word in temp_word.txt echo $onmt_word > temp_word.txt #translate the word in temp_word.txt using openNMT with the model created from a set of 32k words results=$(onmt_translate -gpu -1 -model eng_ipa_model1_steps/eng_ipa_model1_step_100000.pt -src temp_word.txt -replace_unk -verbose -output model1_step_10000_temp_pred) #print only the results we care about, i.e. the translated IPA echo "The provided IPA translation is:" echo $results | egrep -o '< .* >' echo "Please ignore the first and last symbol, these are needed for the translation process." Source: https://github.com/LonelyRider-cs/LING4100_project
Cannot understand why our function calls return twice?
We have a 15 year (or so) old script we are trying to figure out and document. We have found some errors in it but one specific log file gives us much headache. and I would love some help figuring it out. First the function that are run with the question: #=========================================================# # Define function removeOldBackupFile. # #=========================================================# removeOldBackupFile() { #set -x echo "Removing old backups if they exists." >> "${report}" local RCLOC=0 spaceBefore=$(getAvailableSpace ${backupDirectory}) timesToWait=60 # Wait a maximum of 10 minutes before bailing cat ${oldDbContainer} | while read fileName do echo "Old file exists. Removing ${fileName}." >> "${report}" removeFileIfExist "${fileName}" RC=$? echo "Resultcode for removing old backup is: RC=$RC." >> "${report}" RCLOC=$(($RC+$RCLOC)) spaceAfter=$(getAvailableSpace ${backupDirectory}) # Wait for the OS to register that the file is removed cnt=0 while [ $spaceAfter -le $spaceBefore ]; do cnt=$((cnt+1)) if [ $cnt -gt $timesToWait ]; then echo "Waited too long for space in ${backupDirectory}" | tee -a "${report}" RCLOC=$(($RCLOC+1)) return $RCLOC fi sleep 10 spaceAfter=$(getAvailableSpace ${backupDirectory}) done done return $RCLOC } The place where this function is ran looks as follows: #=========================================================# # Remove old backupfiles if any exist. # #=========================================================# removeOldBackupFile RC=$? RCSUM=$(($RC+$RCSUM)) We have identified that the if condition is a bit wrong and the while loops would not work as intended if there are multiple files. But what bothers us is output from a log file: ... + cnt=61 + '[' 61 -gt 60 ']' + echo 'Waited too long for space in /<redacted>/backup' + tee -a /tmp/maintenanceBackupMessage.70927 Waited too long for space in /<redacted>/backup + RCLOC=1 + return 1 + return 0 + RC=0 + RCSUM=0 ... As seen in the log output after the inner loop have ran 60 times and ending it returns 1 as expected.. BUT! it also have return 0 after!? Why is it also returning 0? We are unable to figure out the double returns... Any help appriciated
The first return executes in the subshell started by the pipe cat ${oldDbContainer} | while .... The second return is from return $RCLOC at the end of the function. Get rid of the useless use of cat: removeOldBackupFile() { #set -x echo "Removing old backups if they exists." >> "${report}" local RCLOC=0 spaceBefore=$(getAvailableSpace ${backupDirectory}) timesToWait=60 # Wait a maximum of 10 minutes before bailing while read fileName do ... done < ${oldDbContainer} return $RCLOC }
how to process last x lines of a file
I want to Analyse a logfile for specific Errors. Therefore i want to be able to loop through the last x lines of the files and check every line with a specific REGEX Pattern and then define a specific return value. The logfile Looks in case of success as follows at the Moment when i want to check it. …. sftp> get blahblah/blahblah sftp> bye In case of an Error there is something between the two sftp lines. What i allready tried is to solve the Problem with a specific regex which worked fine on some online Regex testers but couldn´t get it to work in ksh. My current Approach is the following LOG_FIL="test_log" MODE="${1}" check_log_file() { ERRNBR=${1} REGEX=${2} TAIL=${3} RETURN="0" echo "ERRNBR = ${ERRNBR}" echo "REGEX = ${REGEX}" echo "TAIL = ${TAIL}" while read line; do echo "${line}" if [[ "${line}" =~ ${REGEX} ]]; then RETURN="0" echo "bin hier" else RETURN=${ERRNBR} echo "bin wo anders" break fi done <<<$(tail -${TAIL} ${LOG_FIL}) echo "${RETURN}" return ${RETURN} } echo "sftp> get cwi/cdk_final*" >> ${LOG_FIL} if [ "${MODE}" == "1" ]; then echo "Werner ist der beste" >>${LOG_FIL} fi check_log_file "22" "^(sftp> ).*$" "1" echo "$?" echo "sftp> bye" >> ${LOG_FIL} check_log_file "21" "((sftp> ).*|(sftp> bye))" "2" echo "$?" The results i get are the following edv> sh cdk_test4sftp.sh 1 ERRNBR = 22 REGEX = ^(sftp> ).*$ TAIL = 1 Werner ist der beste bin wo anders 22 22 ERRNBR = 21 REGEX = ((sftp> ).*|(sftp> bye)) TAIL = 2 Werner ist der beste sftp> bye bin hier 0 0 What i hoped to achieve was that the Output coming from the tail command would be seperated. So that i ccould test each line individually.
Your second regex: ((sftp> ).*|(sftp> bye)) Matches the following line, which is why your function returns 0: Werner ist der beste sftp> bye Since you want to match the following pattern on each line: sftp> get blahblah/blahblah sftp> bye Your regex should look more like the first one you used to match: ^(sftp> ).*$
BASH script checking log files for current and previous month
I have been working on this on and off for the last two months, and despite how many times I look at it, I can't make it work. This script checks daily log files for a user defined variable, so they don't have to look through every one manually. It worked great checking the current month, but if the user wants to check back 20 days, and today is the 12th of this month, I wanted to be able to then go back to the previous month (not look for the log file with a date of 20150399 and so on). I have checked the logic for my date/day computations, and they seem okay (if there is a better way to do that in BASH, I am open to suggestions). What happens when I try to debug is unexpected end of file. I am somewhat new to writing scripts that contain more than 20 or so lines, but I just can't come up with what I am missing. I have tried various fixes, to no avail, but I think this is the last iteration. Ideas? #!/bin/bash ######################################################## # multi_log_chk.sh # This script will take input from the user and report which # CyberFusion MFT logs contain what the user is looking for. # Hopefully this will save the user having to search through every # stinking log file to find what they are looking for. # 20150406 pxg007 started typing # 20150413 pxg007 added && comparison for back out (line 28) # added message for no entries found (line 32, 38, 48-52) # Added some further description (line 16) # 20150424 pxg007 Added logic to calculate previous month and if necessary, year. (Lines 16-24, 60-78 ) # ######################################################## currDate=`date +%d%B%C%y` currDay=`date +%d` currMnth=`date +%m` currYear=`date +%C%y` case $currMnth in #Let's establish number of days for previous month 05 | 07 | 10 | 12 ) lastMnthD=30;; 01 |02 | 04 | 06 | 09 | 08 | 11 ) lastMnthD=31;; 03 ) lastMnthD=28;; ##and screw leap year esac if [ $currMnth -eq 01 ]; then ##accounting for January lastMnth=12 else lastMnth=$((currMnth-1)) fi if [ $lastMnth -eq 12 ]; then ## accounting for Dec of previous year lastMnthYr=$((currYear-1)) else lastMnthYr=$currYear fi echo "This script will find entries for your query in whatever available MFT logs you request." echo " " echo "For instance - how many log files have transfer entries with \"DOG\" in them?" echo " " echo "I also will also give an estimate of how many transfers per log file contain your query, give or take a couple." echo " " echo "This search is case sensitive, so \"DOG\" is *** NOT *** the same as \"dog\"" echo " " read -p "What text you are looking for? Punctuation is okay, but no spaces please. " looking ### what we want to find echo " " echo "Today's date is: $currDate." echo " " read -p "How many days back do you want to search(up to 25)? " daysBack ### How far back we are going to look if [ "$daysBack" == 0 ] && [ "$daysBack" >> 25 ]; then echo "I said up to 25 days. We ain't got more than that!" exit 1 fi echo " " echo "I am going to search through the last $daysBack days of log files for:\"$looking\" " echo " " read -p "Does this look right? Press N to quit, or any other key to continue: " affirm if [ "$affirm" = N ] && [ "$affirm" = n ]; then ###Yes, anything other than "N" or "n" is a go echo "Quitter!" exit 1 else nada=0 ### Used to test for finding anything backDate=$((currDay-daysBack)) ### current month iterator (assuming query covers only current month) if (("$daysBack" => "$currDay")); then ## If there are more logs requested than days in the month... lastMnthCnt=$((daysBack-currDay)) ### how many days to check last month lastMnthStrt=$((lastMnthD-lastMnthCnt)) ## last month start and iterator backDate=$(currDay-(daysBack-lastMnthCnt)) # Setting the iterator if we have to go back a month while (("$lastMnthStrt" <= "$lastMnthD" )); do foundIt=$(grep "$looking" /CyberFusion/log/Log.txt."$lastMnthYr$lastMnth$lastMnthStrt" | parsecflog | wc -l ) howMany=$((foundIt/40+1)) ### Add one in case there are less than 40 lines in the record. if (("$foundIt" > 0)) then nada=$((nada+1)) echo "Log.txt.$lastMnthYr$lastMnth$lastMnthStrt contains $looking in approximately $howMany transfer records." lastMnthStrt=$((lastMnthStrt+1)) echo " " else lastMnthStrt=$((lastMnthStrt+1)) fi fi backDate=$((currDay-daysBack)) ### current month iterator (assuming query covers only current month) while (("$backDate" <= "$currDay")); do foundIt=$(grep "$looking" /CyberFusion/log/Log.txt."$backDate" | parsecflog | wc -l ) howMany=$((foundIt/40+1)) ### Add one in case there are less than 40 lines in the record. if (("$foundIt" > 0)) then nada=$((nada+1)) echo "Log.txt.$backDate contains $looking in approximately $howMany transfer records." backDate=$((backDate+1)) echo " " else backDate=$((backDate+1)) fi if [ "$nada" \< 1 ] then echo " " echo "I found no entries for $looking in any log file." fi
You are missing the keyword 'done' on lines 81 and 96 and also a final 'fi' keyword on the last line. Also as others suggested you can do date -d "20 days ago" +"%d%B%C%y" to easily get dates in the past
BASH scripts : whiptail file select
I've found a great little program that will allow me to add user friendly GUI's to my Bash Scripts; whiptail However the whiptail man page isn't all that helpful and doesn't provide any examples. After doing some google searches I understand how to create a simple yes/no menu using whiptail: #! /bin/bash # http://archives.seul.org/seul/project/Feb-1998/msg00069.html if (whiptail --title "PPP Configuration" --backtitle "Welcome to SEUL" --yesno " Do you want to configure your PPP connection?" 10 40 ) then echo -e "\nWell, you better get busy!\n" elif (whiptail --title "PPP Configuration" --backtitle "Welcome to SEUL" --yesno " Are you sure?" 7 40) then echo -e "\nGood, because I can't do that yet!\n" else echo -e "\nToo bad, I can't do that yet\n" fi But what I would really like to build a file select menu using whiptail to replace some old code I have in a few different backup/restore bash scripts I have: #!/bin/bash #This script allows you to select a file ending in the .tgz extension (in the current directory) echo "Please Select the RESTORE FILE you would like to restore: " select RESTOREFILE in *.tgz; do break #Nothing done echo "The Restore File you selected was: ${RESTOREFILE}" I assume this has to be done via the '--menu' option of whiptail, but I am not sure how to go about it? Any pointers? Or can you point me in the direction of some whiptail examples?
Build an array of file names and menu select tags: i=0 s=65 # decimal ASCII "A" for f in *.tgz do # convert to octal then ASCII character for selection tag files[i]=$(echo -en "\0$(( $s / 64 * 100 + $s % 64 / 8 * 10 + $s % 8 ))") files[i+1]="$f" # save file name ((i+=2)) ((s++)) done A method like this will work even if there are filenames with spaces. If the number of files is large, you may have to devise another tag strategy. Using alpha characters for the tags lets you press a letter to jump to the item. Numeric tags don't seem to do that. If you don't need that behavior, then you can eliminate some complexity. Display the menu: whiptail --backtitle "Welcome to SEUL" --title "Restore Files" \ --menu "Please select the file to restore" 14 40 6 "${files[#]}" If the exit code is 255, the dialog was canceled. if [[ $? == 255 ]] then do cancel stuff fi To catch the selection in a variable, use this structure (substitute your whiptail command for "whiptail-command"): result=$(whiptail-command 2>&1 >/dev/tty) Or result=$(whiptail-command 3>&2 2>&1 1>&3-) The variable $result will contain a letter of the alphabet that corresponds to a file in the array. Unfortunately, Bash prior to version 4 doesn't support associative arrays. You can calculate the index into the array of the file from the letter like this (notice the "extra" single quote): ((index = 2 * ( $( printf "%d" "'$result" ) - 65 ) + 1 )) Example: Welcome to SEUL ┌──────────┤ Restore Files ├───────────┐ │ Please select the file to restore │ │ │ │ A one.tgz ↑ │ │ B two.tgz ▮ │ │ C three.tgz ▒ │ │ D another.tgz ▒ │ │ E more.tgz ▒ │ │ F sp ac es.tgz ↓ │ │ │ │ │ │ <Ok> <Cancel> │ │ │ └──────────────────────────────────────┘
Whiptail is a lightweight reimplementation of the most popular features of dialog, using the Newt library. I did a quick check, and many features in Whiptail seem to behave like their counterparts in dialog. So, a dialog tutorial should get you started. You can find one here but Google is your friend of course. On the other hand, the extended example probably contains a lot of inspiration for your problem.
This function is part of my function repository for whiptail # ---------------------------------------------------------------------- # File selection dialog # # Arguments # 1 Dialog title # 2 Source path to list files and directories # 3 File mask (by default *) # 4 "yes" to allow go back in the file system. # # Returns # 0 if a file was selected and loads the FILE_SELECTED variable # with the selected file. # 1 if the user cancels. # ---------------------------------------------------------------------- function dr_file_select { local TITLE=${1:-$MSG_INFO_TITLE} local LOCAL_PATH=${2:-$(pwd)} local FILE_MASK=${3:-"*"} local ALLOW_BACK=${4:-no} local FILES=() [ "$ALLOW_BACK" != "no" ] && FILES+=(".." "..") # First add folders for DIR in $(find $LOCAL_PATH -maxdepth 1 -mindepth 1 -type d -printf "%f " 2> /dev/null) do FILES+=($DIR "folder") done # Then add the files for FILE in $(find $LOCAL_PATH -maxdepth 1 -type f -name "$FILE_MASK" -printf "%f %s " 2> /dev/null) do FILES+=($FILE) done while true do FILE_SELECTED=$(whiptail --clear --backtitle "$BACK_TITLE" --title "$TITLE" --menu "$LOCAL_PATH" 38 80 30 ${FILES[#]} 3>&1 1>&2 2>&3) if [ -z "$FILE_SELECTED" ]; then return 1 else if [ "$FILE_SELECTED" = ".." ] && [ "$ALLOW_BACK" != "no" ]; then return 0 elif [ -d "$LOCAL_PATH/$FILE_SELECTED" ] ; then if dr_file_select "$TITLE" "$LOCAL_PATH/$FILE_SELECTED" "$FILE_MASK" "yes" ; then if [ "$FILE_SELECTED" != ".." ]; then return 0 fi else return 1 fi elif [ -f "$LOCAL_PATH/$FILE_SELECTED" ] ; then FILE_SELECTED="$LOCAL_PATH/$FILE_SELECTED" return 0 fi fi done } The use is simple if dr_file_select "Please, select a file" /home/user ; then echo "File Selected: \"$FILE_SELECTED\"." else echo "Cancelled!" fi
I've tried following, which worked: whiptail --title "PPP Config" --backtitle "Welcome to SEUL" --menu YourTitle 20 80 10 `for x in $(ls -1 *.tgz); do echo $x "-"; done` you might change this into a multiple-liner as well, i've added checking for empty list: MYLIST=`for x in $(ls -1 *.tgz); do echo $x "-"; done` WC=`echo $MYLIST | wc -l` if [[WC -ne 0]]; then whiptail --title "PPP Config" --backtitle "Welcome to SEUL" --menu YourTitle 20 80 10 $MYLIST fi you need to adjust the numbers in order to get a cleaninterface. And you may replace the "-" by anything else if you want to. But if you don't, you will see 2 entries per line. By the way: The selected entry is printed onto stderr. This could need some more improving, but for a basic idea I think it's enough.
This seems to be one of the top results when you search for whiptail, and none of the previous results worked for me. This is what I wound up using: #! /bin/bash shopt -s nullglob dir=`pwd` cd /path/to/files arr=(*.tgz) for ((i=0; i<${#arr[#]}; i++)); do j=$((2*$i+2)); a[j]="${arr[$i]}"; a[j+1]=""; done a[0]="" # Next line has extra spaces at right to try to center it: a[1]="Please make a selection from the files below " result=$(whiptail --ok-button "OK button text" --cancel-button "Cancel Button Text" --title "Title Text" --backtitle "Text at upper left corner of page" --menu "Menu Text (not used??)" 30 160 24 "${a[#]}" 2>&1 >/dev/tty) if [[ $? = 0 ]] then # ge 5 in next line should be length of file extension including . character, plus 1 [ ${#result} -ge 5 ] && outfile="/path/to/files/$result" || echo "Selection not made" fi cd "$dir" $result will be empty if no valid selection was made. I added a dummy selection at the top of the list that returns an empty string as a result, so that you won't accidentally select the wrong file by accidentally hitting Enter right after the menu comes up. If you don't want that, then in the "for" line remove the +2 in "do j=$((2*$i+2))" and also the following two lines that set a[0] and a[1] explicitly. The confusing thing about whiptail is that when reading from an array in a situation like this it expects two data items per line, both of which are displayed, the first being the result you want returned if the line is expected (which in some situations might be a letter or a number) and the second being whatever descriptive text you may want. That's why for the first line I use a[0] to give an empty string as the result, and a[1] as the descriptive text, but from there on the first item in the pair contains the filename (which is what I actually want returned) and the second is an empty string, since I don't want to display any text other than the filename on those lines. Also a previous post said whiptail returned an error code of 255 if the cancel button was pressed, but that was not the case for the version I have - it returns 1. So I just test for an error code of 0 and if it is I assume it may be a valid entry, then I test for a valid string length (more than just the number of characters in the file extension, including the . character) to be sure.