0

Currently I'm writing a bash script that is supposed to loop over some files in a directory in order of the creation date. To do so I use (with real code instead of the echo):

for i in $(ls -tr)
do
    echo $i
done

which works fine most of the time.

But now I found a type of file that breaks the script: aha_-_a ()a.txt.

This filename contains a blank followed by an opening parentheses " (" which seems to trigger a newline. The result is:

aha_-_a
()a.txt

But it should be:

aha_-_a ()a.txt

Do you have any idea how to get the desired behavior?

1

1 Answer 1

5

Leaving $(ls -tr) unquoted invokes split+glob upon the expansion.

The splitting is done based on the characters of $IFS (by default SPC, TAB and NL) and then the glob part will look for wildcard characters in there and try to expand the files matching the corresponding patterns.

Here, it looks like you actually want to split the output of ls on NL characters only and not do the glob part. So it should be:

IFS=$'\n' # split on NL only
set -o noglob # disable the glob part
for f in $(ls -tr); do
  printf '%s\n' "$f"
done

That will then work OK for your files containing SPC characters. It will however still not work if there are filenames with NL characters.

Here, best would be to switch to zsh and do:

for f in *(NOm); do
  printf '%s\n' "$f"
done

Where * expands to all the non-hidden files in the current directory sorted in reverse by age like ls -rt does with the Om glob qualifier (the N one (for nullglob) avoids the error if there's no matching file).

Or if you have GNU ls, with bash:

eval "files=($(ls --quoting-style=shell-always -rt))"
for f in "${files[@]}"; do
  printf '%s\n' "$f"
done

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .