One of the most basic tools for locating files (or other kinds of nodes) is the find
utility.
find ./ -type f -name '*[!0-9][0-9].txt'
This will search:
- ...recursivly from the current directory (
./
). You could change this to another path or even leave it off since this is the default value for most versions of find
.
- ...for items that are files as opposed to directories, devices nodes, symbolic links, etc (
-type f
). You could leave this off if you wanted to find other types too.
- ...for items that match the name pattern given. Note that I have used single quotes to encose the pattern so that bash or your shell does not try to expland it to a glob pattern before find even gets the command. The star matches any number of characters, then the end of the file must be something other than a digit, then a digit, then your extention. (
-name '*[0-9].txt'
)
If there are files whose name is only a digit followed by .txt
, the command above will miss them, because it requires one non-digit before the digit. The following equivalent commands use boolean operators to include file names with just a digit as well (-o
is “or” and !
is “not”):
find ./ -type f \( -name '*[!0-9][0-9].txt' -o -name '[0-9].txt' \)
find ./ -type f -name '*[0-9].txt' ! -name '*[0-9][0-9].txt'
Note that this will be case sensitive. If you would like an insensitive match, you can use -iname
instead of -name
to match things like file4.TXT
as well. Also be aware that just because a file claims to be a text file with that extention does not mean it is. On linux any file can be any type no matter the name. There might also be text files with other extentions or with no extention at all.
I am not at all convinced of this, but let's suppose for the sake of argument that you could, if you're prepared to put in enough effort, parse the output of ls
reliably, even in the face of an "adversary" — someone who knows the code you wrote and is deliberately choosing filenames designed to break it.
Even if you could do that, it would still be a bad idea.
Bourne shell is not a good language. It should not be used for anything complicated, unless extreme portability is more important than any other factor (e.g. autoconf
).
I claim that if you're faced with a problem where parsing the output of ls
seems like the path of least resistance for a shell script, that's a strong indication that whatever you are doing is too complicated for shell and you should rewrite the entire thing in Perl or Python. Here's your last program in Python:
import os, sys
for subdir, dirs, files in os.walk("."):
for f in dirs + files:
ino = os.lstat(os.path.join(subdir, f)).st_ino
sys.stdout.write("%d %s %s\n" % (ino, subdir, f))
This has no issues whatsoever with unusual characters in filenames -- the output is ambiguous in the same way the output of ls
is ambiguous, but that wouldn't matter in a "real" program (as opposed to a demo like this), which would use the result of os.path.join(subdir, f)
directly.
Equally important, and in stark contrast to the thing you wrote, it will still make sense six months from now, and it will be easy to modify when you need it to do something slightly different. By way of illustration, suppose you discover a need to exclude dotfiles and editor backups, and to process everything in alphabetical order by basename:
import os, sys
filelist = []
for subdir, dirs, files in os.walk("."):
for f in dirs + files:
if f[0] == '.' or f[-1] == '~': continue
lstat = os.lstat(os.path.join(subdir, f))
filelist.append((f, subdir, lstat.st_ino))
filelist.sort(key = lambda x: x[0])
for f, subdir, ino in filelist:
sys.stdout.write("%d %s %s\n" % (ino, subdir, f))
Best Answer
It seems you can't do this with
dircolors
, but you can do it by modifyingLS_COLORS
directly:dircolors
only seems to handle three types of descriptors: terminal names (starting withTERM
), file types (e.g.DIR
), and extensions starting with.
. The latter get expanded by prefixing them with*
; so your.*~
becomes*.*~
, which only matches backup files containing a.
.ls
itself can interpret more generalLS_COLORS
entries such as*~
, which matches all files ending with~
.