Issue
The goal is to be able to manually select a file process order, and if the user is not at the computer then let the script select based upon the quantity of files to process.
a) Many files -gt 5 then process smallest files first
b) 5 or less then process the oldest file first
I started simple with just CASE and that is working.
Next I introduced an IF which is also working.
CountMp4=$(ls *.mp4 | wc -l)
while :
do
read -t50 -p "Select a File Processing Order - [A]lpha [O]ldest [N]ewest [L]argest [S]mallest: "
if [ $? -gt 0 ]; then
SelectedFileName=$( ls -rt *.mp4 | head -1 ) && echo -e "No Option Selected\nWill use the Oldest file: $SelectedFileName" && break
fi
case $REPLY in
[aA]*)
SelectedFileName=$( ls *.mp4 | head -1 ) && echo "Alphabetical: $SelectedFileName" && break
;;
[oO]*)
SelectedFileName=$( ls -rt *.mp4 | head -1 ) && echo "Oldest: $SelectedFileName" && break
;;
[nN]*)
SelectedFileName=$( ls -t *.mp4 | head -1 ) && echo "Newest: $SelectedFileName" && break
;;
[lL]*)
SelectedFileName=$( ls -S *.mp4 | head -1 ) && echo "Largest: $SelectedFileName" && break
;;
[sS]*)
SelectedFileName=$( ls -rS *.mp4 | head -1 ) && echo "Smallest: $SelectedFileName" && break
;;
*) echo "Please enter A, O, N, L or S"
;;
esac
done
Now I am trying to introduce an ELSE to the IF, but this is where I am stuck.
Perhaps I am going about the solution in the wrong way.
Any guidance is appreciated.
CountMp4=$(ls *.mp4 | wc -l)
while :
do
read -t50 -p "Select a File Processing Order - [A]lpha [O]ldest [N]ewest [L]argest [S]mallest: "
if [ $? -gt 0 ] && [ $CountMp4 -gt 5 ]; then
SelectedFileName=$( ls -rS *.mp4 | head -1 ) && echo -e "No Option Selected\nMany files, using the Smallest file: $SelectedFileName" && break
else
SelectedFileName=$( ls -rt *.mp4 | head -1 ) && echo -e "No Option Selected\nWill use the Oldest file: $SelectedFileName" && break
fi
case $REPLY in
[aA]*)
SelectedFileName=$( ls *.mp4 | head -1 ) && echo "Alphabetical: $SelectedFileName" && break
;;
[oO]*)
SelectedFileName=$( ls -rt *.mp4 | head -1 ) && echo "Oldest: $SelectedFileName" && break
;;
[nN]*)
SelectedFileName=$( ls -t *.mp4 | head -1 ) && echo "Newest: $SelectedFileName" && break
;;
[lL]*)
SelectedFileName=$( ls -S *.mp4 | head -1 ) && echo "Largest: $SelectedFileName" && break
;;
[sS]*)
SelectedFileName=$( ls -rS *.mp4 | head -1 ) && echo "Smallest: $SelectedFileName" && break
;;
*) echo "Please enter A, O, N, L or S"
;;
esac
done
When I introduce ELSE to the IF, I break the CASE.
Solution
Don't create 2 separate ways of getting results, just let the one case
statement handle it:
CountMp4=$(ls *.mp4 | wc -l)
while :
do
read -t50 -p "Select a File Processing Order - [A]lpha [O]ldest [N]ewest [L]argest [S]mallest: "
if [ $? -gt 0 ]; then
if [ $CountMp4 -gt 5 ]; then
echo -e "No Option Selected, many files, use the Smallest file"
REPLY='S'
else
echo -e "No Option Selected, few files, use the Oldest file"
REPLY='O'
fi
fi
case $REPLY in
[aA]*)
SelectedFileName=$( ls *.mp4 | head -1 ) && echo "Alphabetical: $SelectedFileName" && break
;;
[oO]*)
SelectedFileName=$( ls -rt *.mp4 | head -1 ) && echo "Oldest: $SelectedFileName" && break
;;
[nN]*)
SelectedFileName=$( ls -t *.mp4 | head -1 ) && echo "Newest: $SelectedFileName" && break
;;
[lL]*)
SelectedFileName=$( ls -S *.mp4 | head -1 ) && echo "Largest: $SelectedFileName" && break
;;
[sS]*)
SelectedFileName=$( ls -rS *.mp4 | head -1 ) && echo "Smallest: $SelectedFileName" && break
;;
*) echo "Please enter A, O, N, L or S"
;;
esac
done
BUT you have several other issues to clean up in your script, start by copy/pasting it into http://shellcheck.net and fixing what that tool tells you about and then consider doing something like this, untested:
#!/usr/bin/env bash
selectFile() {
printf '%s\n' "${files[@]}" | sort "$@" | head -1 | cut -f3-
}
readarray -t files < <(find . -name '*.mp4' -printf '%A@\t%s\t%P\n')
if (( ${#files[@]} > 5 )); then
dfltReply='S'
else
dfltReply='O'
fi
while :
do
if ! read ....; then
printf 'read failed, using default %s\n' "$dfltReply" >&2
REPLY="$dfltReply"
fi
case $REPLY in
[aA]*) SelectedFileName=$(selectFile -k3) && break ;;
[oO]*) SelectedFileName=$(selectFile -nrk1) && break ;;
...
*) printf 'Please enter A, O, N, L or S\n' ;;
esac
done
The main part is to use find
to find the files, print their latest modification time, size, and name, and store that list in an array, files[]
. From then on you just pipe the array contents to sort
with appropriate options followed by head
and cut
to get the file name you need in each case.
The above is assuming your file names cannot contain newlines - if they can then change -printf '%A@\t%s\t%P\n'
to -printf '%A@\t%s\t%P\0'
, add the -z
option to sort
, head
, and cut
(requires GNU tools), change printf '%s\n' "${files[@]}"
to printf '%s\0' "${files[@]}"
and change the way selectFile()
is implemented and called to some variation of:
selectFile () {
IFS= read -d '' -r "$1" < <(
printf '%s\0' "${files[@]}" | sort -z "$2" | head -z -n 1 | cut -z -f3-
)
}
selectFile SelectedFileName -k3
because command substitution var=$(func)
doesn't support NUL bytes in the assignment.
Answered By - Ed Morton Answer Checked By - Gilberto Lyons (WPSolving Admin)