Reading User Input in Linux

I have written a script for listing files based on the month which is read by the user as below:-

echo "Enter Month"
read month
ls -al | awk '$6 == "$month" {print}'

And i am giving the user input as Aug, i am not getting any result. But when i am writing

ls -al | awk '$6 == "Aug" {print}'

I am getting the exact result. Am i doing something wrong? Please help


Solution 1:

The main thing is: variable names are not expanded inside single quotes. This is a "better" (i.e. a little less wrong) line:

ls -al              | awk '$6 == "'"$month"'" {print}'
# this is in single quotes ^^^^^^^          ^^^^^^^^^

But:

  1. Still this may fail in some locales. Set LC_ALL=C beforehand or so maybe.
  2. With $month you can inject (almost?) anything into awk. There are better ways to use variables within awk; -v option should be a lot safer (thank you user000001 for pointing this out).
  3. You shouldn't parse the output of ls in the first place.

The right solution might use find and stat. The following code may not be the fastest solution but it's more robust due to:

  • discarding $month values that don't match predefined ones,
  • using find instead of parsing ls.

The code:

#!/bin/sh
echo "Enter Month"
read month
case "$month" in
  1|01|Jan|jan|January|january)   monthN=01;;
  2|02|Feb|feb|February|february) monthN=02;;
# ...
  10|Oct|oct|October|october)     monthN=10;;
# ...
  *) echo Error! >&2; exit 1;;
esac
find ./ -maxdepth 1 -exec sh -c '[ `stat -c %y "$1" | cut -c 6-7` = "$2" ]' sh {} "$monthN" \; -ls

I tested this on Debian; it may not be super-portable. It shows the general approach though.

The last line invokes a separate shell for every object in the current directory (including ./ itself). This shell uses stat to get mtime information, then cut extracts two-digit month number from it. [ ... ] compares the result to the chosen month number. If this test succeeds then find performs its own ls on the object (you may use -print or -print0 instead).

Note this never returns ../. On the other hand find allows you to use additional tests (like -type f), so this approach is very flexible.