user1011471 user1011471 - 5 months ago 16
Linux Question

POSIX glob -- how to match one-or-more [:digit:]

I want to iterate over

foo.log
and its log rotated siblings
foo.1.gz
and
foo.2.gz
from newest to oldest, with code that isn't fooled by the presence of
foo.bar


Happily,
logrotate
names things such that newest-to-oldest and alphabetical are the same ordering.

My original attempt was
for f in $(ls -t foo.*); do ...
but
shellcheck
said
Iterating over ls output is fragile. Use globs. [SC2045]
. Plus this code matches
foo.bar
which is not desired.

But how do you match an arbitrary number of digits with a glob pattern? (Or is this not supported?) I only know how to list each number of digits explicitly. For example, the following handles 1 and 2 digit numbers and correctly excludes
foo.1bar.gz
but doesn't handle
foo.123.gz
(and I'm not doing the right thing to cause
glob
ing to take place!)

for f in foo.log foo.[[:digit:]].gz foo.[[:digit:]][[:digit:]].gz; do ...


I could assume that no one keeps over 100 log rotated siblings, but I'd prefer not to.

Looking for a POSIX compliant solution...

Edit: the logrotate conf compresses for some files and doesn't compress for others. So not all siblings end in
.gz
.

Answer

A glob pattern is not a regular expression. See glob(7) for the syntax.

There is no glob pattern to match a series of digits. You can get close with foo.[0-9]*.gz. If that picks up some names you don't want, you can filter them out with a regex, maybe something like:

echo foo.[0-9]*.* | tr ' ' \\n | grep -E '[.][0-9]+([.]gz)?$' 

You can probably use a glob pattern and rely on the shell for ordering, given the constraints you presented. You can check if your shell renders filenames for a glob pattern in sorted order with sort:

echo foo.[0-9]*.gz | tr \  \\n | sort -c

But it's also OK to parse the output of ls -t unless you're being extremely rigorous. The guidance from shellcheck is good advice: many people seem to want to parse ls output when a simple glob would do, and to depend on ls to behave the same way across different systems is to invite error. That said, you're only asking for ls to sort the filenames by time, producing a single column of output. Anything else you might do would be more error-prone.

Comments