简体   繁体   中英

bash wildcard expansion with a set construct

Bash wildcard expansion.

I have a direcotry with three files in it. I want to use wilcar expansion to match program.c and program.o

casper@casper-PC ~
$ ls -ltr
total 4
drwxr-xr-x+ 1 casper None 0 Apr 12 18:31 perl_lwp
-rw-r--r--  1 casper None 0 Apr 25 00:14 program.o
-rw-r--r--  1 casper None 0 Apr 25 00:14 program.c
-rw-r--r--  1 casper None 0 Apr 25 00:14 program.log

This does not work.

casper@casper-PC ~ 
$ ls -ltr | egrep program.[co]

Nor does this work.

 casper@casper-PC ~ 
$ ls -ltr | egrep program.?

This does not work

casper@casper-PC ~
$ grep -r program.?

this does work - but I wanted to use bash brace expansion, not perl.

casper@casper-PC ~
$ ls -ltr | perl -nle 'print /(program.[co])/'
program.o
program.c

However I thought it strange that it matches both of them because I thought that the set construct would match o or c and then stop once it matched

Use set -x to see what is happening. Since you are using wildcards ( glob constructs ) outside quotes, the shell expands the filenames before egrep gets run.

If you want to pass patterns to a program, enclose them inside 'single quotes' .

Don't confuse globbing with regular expressions - they are different pattern matching regimes. For example:, in regular expressions ? means "zero or more of the preceding pattern", whereas in globbing it means exactly one character.

program.? in a regular expression means "program" followed by an optional single character ( . means one of any character except newline) somewhere in the string .

program.? in globbing means "program." followed by one single character.

egrep takes regular expressions, not glob constructs.

This is also possibly an unnecessary use of both ls and egrep , just use echo :

echo program.[co]
   program.c program.o
echo program.?
   program.c program.o

This works because echo is a shell built-in and the shell does globbing (and is generally more efficient than calling an external program like ls ).

Now your Perl snippet worked for two reasons. One: you enclosed the pattern inside single quotes, which you didn't do for the egrep .

Two: you just happened to pick the only pattern which is the same in regular expressions and globbing - the [ ] character-class notation (although there are even differences here). The /.../ notation in Perl invokes the regular expression match ( m ) operator by default.

You expected the Perl match to stop on the first match, but the -nl options means that it performs the print statement in a loop for each line in standard-input, which comes from the pipe.

BTW, Perl also has the built-in function glob() .

echo *|perl -nle 'print glob("program.[co]")'

You could try adding end of the line anchor and also put the regex inside quotes. Note that grep uses regex to find strings not glob.

ls -ltr | grep 'program\.[co]$'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM