Issue
Currently, I am doing this in a bash script.
for i in $(ls -tr *.tar); do
# something
done
When I run shellcheck
, I got a (correct) warning
for i in $(ls -tr *.tar); do
^-------------^ SC2045 (warning): Iterating over ls output is fragile. Use globs.
OK, but what to do here? I cannot use globs, or at least I don't know how.
I will add I need to keep the order as ls -tr
does, that is, ordered by time modified (and reversed, newest at the bottom).
I have seen some ways to do this, some of them on Stack Overflow (for example In a bash script how to loop through files sorted by date ), doing find/sort/awk combo, but that all seem even more fragile than just using ls
.
Is there a safe way to do this? (I am using Linux with "standard" coreutils etc)
Solution
Largely, this is covered by BashFAQ #3; the below extracts a relevant subset.
On a GNU system, find
's -printf
can print timestamp metadata.
Using NUL-delimited output and sort -z
ensures correct operation with all possible filenames, including ones with literal newlines included (the NUL is the only character that cannot possibly exist in a path across all UNIXy systems).
while IFS= read -r -d : time && IFS= read -r -d '' file; do
echo "Read ${file} with timestamp ${time}"
done < <(find "$dir" -mindepth 1 -maxdepth 1 -type f -printf '%T@:%p\0' | sort -zn)
The use of -printf
ensures a well-defined output format, and is thus (assuming, again, availability of GNU tools) not at all fragile.
If you want to reverse the order and list newest-to-oldest, add the -r
argument to sort
.
Answered By - Charles Duffy Answer Checked By - David Goodson (WPSolving Volunteer)