Getting input from a user is one of the most useful (and risky) things programmers do.
This is where the process of validating input comes in.
Serious data validation is beyond the scope of this site, but we will cover some basic user input to get you started.
This site is designed for a single user doing scripting at home, so we will continue on that premise.
You may be just curious about bash programming, or you may definitely require to learn more about it. For example, I use bash scripts to enter data into several personal databases I maintain at Web Mechanic.
If you are the only person entering text into your scripts and running them, then you should be fine.
Using echo and printf are one half of the system I/O facility. This is the other half: getting user input.
Getting input from a user is a common task, so with no further ado, let's get at it.
You need to get a birth date from a user in your script. Here is one way.
As always, our scripts begin with the shebang and location of the bash shell:
#!/usr/local/bin/bash printf "%s" "Enter your date of birth (yyyy-mm-dd):" read BirthDate printf "%s" "Is $BirthDate correct? (y/n):" read BirthResponse echo $BirthResponse echo read -s -p "Please enter your password: " passwd echo printf "%s""\nI think your password is -->$passwd<--\n"
Here we've asked for a date of birth, and assigned it to the variable BirthDate.
Then asked for a y or n response, and assigned it to the variable BirthResponse.
Lastly, we've asked for a password, and assigned it to passwd.
Two useful options to the read command are -s and -p, which we used asking for a password.
The -s does not echo the response to the screen (silent), so anyone looking over your shoulder won't know what you're typing.
And -p prints the prompt before reading the input.
But we haven't checked whether the user entered y or n (or something else) for the BirthDate.
One test we can do is check whether a variable contains anything or is empty.
#!/usr/local/bin/bash # input2.sh # test input for content VAR="$1" if [ "$VAR" ] then echo Not empty else echo Zero length;echo Please enter something fi
Copy and paste type the above code into a new file in your text editor, and save to your ~/bin/bash directory.
Setting VAR to "$1" is looking for an argument when you run the script.
You can run the script with an argument in double quotes, or with nothing. Do both to see what happens.
./input2.sh Zero length Please enter something
./input2.sh "There is some text in here somewhere" Not empty
In the then block of code, you can provide whatever code is suitable for the situation.
And the else block of code requires your own decision as well.
A rather simple test, but it may be all you need. More complex testing is possible though.
Getting input from a user via the keyboard is 1 way of getting data, but much of scripting depends on doing something with data that exists already in a file.
For example we may have
Another source of input may be from an operation or command we are running in Terminal, and we want to perform some operation on it. More about this in Mathematics and Redirection.
As long as the file is made of pure ASCII text we can do many things with the content.
We can get input from a text file a few ways. We can redirect it into our script or command.
We have a file of track names and play times from a CD:
01 - Vira Poeira Burning To Dust.flac|0:04:47 02 - Come As You Are.flac|0:04:46 03 - 700 Years.flac|0:04:39 04 - After These Messages.flac|0:03:03 05 - Street Vendors D'JMBO.flac|0:05:03 06 - Wake Up Now.flac|0:05:03 07 - Homeless Around The Fire.flac|0:06:19 08 - Samba 4 Sale.flac|0:06:59 09 - Ginga Sem Fronteira.flac|0:04:42
Copy and paste that text into a new text file named 'track-times.txt' in a directory. Then 'cd' to that directory if you aren't already there.
In Terminal, doing a 'cd' to another directory (perhaps on another drive) can involve quite a bit of typing, which is an excellent source of errors. This is where I use a little 'magik'.
In the Finder window, open it to the directory you want to 'cd' to.
Then in the Terminal window, enter 'cd ' - make sure there is a space after 'cd'.Then in Finder, drag the icon of the target directory into the Terminal window, and drop it after the 'cd ' you just entered.
Now hit 'return' / 'enter' in Terminal, and it will do it for you.
A handy use of drag-and-drop.
We see that the running times of each track are separated by the pipe | character. Using that, we can write a script to separate them from each line, and write them to a new file.
Now to write the script...
#!/usr/local/bin/bash
# split text into 2 on the '|'
clear
if [ -z "$1" ]
then
echo 'Please give me a filename to work on eh!'
exit 0
fi
[ -n "`file $1|grep text`" ] && { # is it a text file?
echo "$1 is a text file"
} || { # or
echo "$1 isn't a text file"
exit 0
}
# if we get this far, it's a text file
InFile=$1
echo "Complete lines:"
cat $InFile;echo # print whole file
jot -b '=' -s '' 20 # print '=' 20 times
echo "Tracks only:"
# pipe output to awk with Field Separator of '|'
cat $InFile | awk 'BEGIN{FS="\|" }{print $1}'
jot -b '=' -s '' 20 # print '=' 20 times
echo "Times only:"
cat $InFile | awk 'BEGIN{FS="\|" }{print $2}' # >> times.txt
jot -b '=' -s '' 20 # print '=' 20 times
But it does what we wanted:
track-times.txt is a text file Complete lines: 01 - Vira Poeira Burning To Dust.flac|0:04:47 02 - Come As You Are.flac|0:04:46 03 - 700 Years.flac|0:04:39 04 - After These Messages.flac|0:03:03 05 - Street Vendors D'JMBO.flac|0:05:03 06 - Wake Up Now.flac|0:05:03 07 - Homeless Around The Fire.flac|0:06:19 08 - Samba 4 Sale.flac|0:06:59 09 - Ginga Sem Fronteira.flac|0:04:42 ==================== Tracks only: 01 - Vira Poeira Burning To Dust.flac 02 - Come As You Are.flac 03 - 700 Years.flac 04 - After These Messages.flac 05 - Street Vendors D'JMBO.flac 06 - Wake Up Now.flac 07 - Homeless Around The Fire.flac 08 - Samba 4 Sale.flac 09 - Ginga Sem Fronteira.flac ==================== Times only: 0:04:47 0:04:46 0:04:39 0:03:03 0:05:03 0:05:03 0:06:19 0:06:59 0:04:42 ====================
If the output of each step needs to be saved to a file, that can be done as shown in 2nd-last line of the script:
cat $InFile | awk 'BEGIN{FS="\|" }{print $2}' # >> times.txt
recall that '>>' appends output to a file.
Just remove the '#' to write output to the file.
Many times we want to compare a user input or a variable to an existing value. There are 2 forms of this test:
For string comparison:
For numeric comparison
Save this code in a new file input3.sh as before.
#!/usr/local/bin/bash # input3.sh # test input for equality MyVar="OICURMT" VAR="$1" if [ "$VAR" == "$MyVar" ] then echo "Yep! They're the same" else echo "Nope, try again..." fi
When you run it with and without any input, you should see ...
./input3.sh Nope, try again... ./input3.sh "oicurmt" Nope, try again... ./input3.sh "OICURMT" Yep! They're the same
To check numeric input:
#!/usr/local/bin/bash # input3.sh # test input for equality MyVar="1337" VAR="$1" if [ "$VAR" -eq "$MyVar" ] then echo "Yep! They're the same" else echo "Nope, try again..." fi
./input3.sh ./input3.sh: line 6: [: : integer expression expected Nope, try again... ./input3.sh 1733 Nope, try again... ./input3.sh 1337 Yep! They're the same
An important feature to know about user input, is whether they are entering straight text (ASCII) or binary code, such as a .jpg file.
This may not be a concern if YOU are the one entering the data, but if you are writing code to be run on a different computer, or if others have access to your computer, this would be something to be concerned with.
One command that can be used is file.
#!/usr/local/bin/bash # whatis.sh # determine type of file file "$1"
Recall that $1 refers to the first argument supplied to the script on the command line:
file "WhatKindOfFileIsThis.fubar"
Run the script like this:
/bin/bash/whatis.sh "01 - Omax 1 (Tokyo).flac" 01 - Omax 1 (Tokyo).flac: FLAC audio bitstream data, 16 bit, stereo, 44.1 kHz, 19328736 samples
This may output a few lines of text. I've tested several file formats:
With this knowledge, we should be able to construct a test to determine what to do with that file.
It seems that the files that really are ASCII / text have 'text' in the response. SVG and JSON files are also plain text.
Note that '.odt Open Document Text' files are NOT plain text or ASCII, even though this result says so.
By accident I also had a '.cue' named as a '.que' file, but the response was as though it were named correctly. This leads one to believe that the file program is not merely looking at file extensions.
So we can check for 'text' in the response, or if the file extension is .svg or .json we can assume they are ASCII as well.
If you deal with files other than those above, your mileage may vary, so be aware.
In a directory (test) I have several files of various formats:
Bruce Katz Band - Get Your Groove.cue conway-life-glider.svg cover.jpg ffmpeg-115034-ge09164940e.7z FileZilla_3.68.1_macos-x86.app.tar.bz2 id_rsa.1684544711.pub Joel Ross - early.flac linuxmint-21.3-cinnamon-64bit-edge.iso platypus.zip Plex-1.6.5.1097-3bb9dc68-x86_64.zip Plex.app redirect.pages ruby2.rb shotcut-macos-241117.dmg UnicodeData.txt
Adding a bit of magic to the whatis.sh script:
#!/usr/local/bin/bash # whatis.sh # determine type of file file test/* | grep 'text'
Making a pipeline with grep, we accomplish in 1 line of code several steps. When I run the script, results are:
whatis.sh test/Bruce Katz Band - Get Your Groove.cue: ASCII text, with CRLF line terminators test/UnicodeData.txt: ASCII text test/ruby2.rb: Ruby script text executable, ASCII text
This goes a long way to helping us determine what kind of file we might be working with.
At this point we would need to check each response to see if contains the string 'text' in lower case.
I will leave this an exercise for the reader.