Simply because there's no such thing as a &(...)
operator in bash
. bash
only implements a subset of ksh
patterns with extglob
. Here you want:
grep -Fwn Foo /**/src/**/!(Foo).@(h|cpp)
With ksh93
, you can use &
this way:
grep -Fwn Foo /**/src/@(*.@(h|cpp)&!(Foo*))
zsh
has a and-not operator with extendedglob
:
grep -Fwn Foo /**/src/(*.(h|cpp)~Foo*)
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
Are you really doing globbing, i.e. wildcard expansion? For example, suppose that you have a directory called
Foobar
. Thendoesn't do globbing, because there is no wildcard character. When you specify a file name exactly, it's up to the application to decide what to do with it, and since unix file names are case sensitive, the application will not open a file called
Foobar
if you tell it to open a file calledfoobar
.On the other hand,
will change to the
Foobar
directory (assuming there is no other match), if you've set thenocaseglob
option.You can make completion case-insensitive too. Put
set completion-ignore-case on
in~/.inputrc
, orin
~/.bashrc
. Then after enteringcd foo
and pressing Tab, the shell will completeFoobar
.