I need to list only the files in a directory that do NOT begin with qc_dl, qc_dt or qd_df, but that also DO end in .sas.

I can list the files that do not begin with "qc_dl" as such:

ls -I "qc_dl*" 

But then I do not know how to only select the SAS programs from the resultant list.

Furthermore, I can select all SAS files that begin either with "qc_dl", "qc_dt" or "qd_df", as follows:

ls qc_d{l,t,f}*.sas

However, I cannot combine the two commands to only list SAS files that DO NOT begin with qc_dl/t/f.


Assuming file names don't contain newline characters and don't start with ., this should work:

ls -d -- *.sas | grep -v '^qc_d[ltf]'

List files ending in .sas and filtering all that is NOT qc_dl, qc_dt, qc_df

For any filtering needs, grep is your friend.


Use find instead?

find /my/example/dir -type f -name '*.sas' ! -name 'qc_d[ltf]*'

From man bash:

If the extglob shell option is enabled using the shopt builtin, several extended pattern matching operators are recognized. In the following description, a pattern-list is a list of one or more patterns separated by a |. Composite patterns may be formed using one or more of the following sub-patterns:

                 Matches zero or one occurrence of the given patterns
                 Matches zero or more occurrences of the given patterns
                 Matches one or more occurrences of the given patterns
                 Matches one of the given patterns
                 Matches anything except one of the given patterns

You can then use more powerful pattern matching when this is enabled.

To turn it on:

~$ shopt -s extglob

Then you can list files that end with .sas and do not begin with qc_d:

~$ ls
a.sas  a.txt  b.sas  b.txt  c.sas  c.txt  qc_dc.sas  qc_df.sas  qc_dl.sas  qc_dt.sas
~$ ls !(qc_d*).sas
a.sas  b.sas  c.sas

To turn it off:

~$ shopt -u extglob
  • Brilliant, thanks. I combined qc_d[ltf] to get all three options, because there are some qc_d*.sas programs that I need, eg. qc_demo.sas. So final command was: > ls !(qc_d[ltf]*).sas – Syan Dec 11 '14 at 16:02
ls -d [![.qc_dl.][.qc_dt.][.qd_df.]]*.sas

reference "man 7 glob"
[!...] -> any thing but not in that class equivalent to [^...] in grep or regex
[.qc_dl.] -> accurate pattern to mach exactly "qc_dl" inside 
class rather than any character or range occurrence  

scenario: hey mr shell please list for me all things not starting
in "qc_dl" nor "qc_dt" nor "qd_df"  but if any of them ending
with .sas then its ok you can list them. 

$ touch qc_dloooooooo.sas
$ touch qc_dloooooooo
$ touch qc_dtfffghhjh.sas
$ touch qc_dtfffghhjh
$ touch cvvvbkkk
$ touch cvvvbxcvvcxv
$ ls -d [![.qc_dl.][.qc_dt.][.qd_df.]]*.sas
qc_dloooooooo.sas  qc_dtfffghhjh.sas

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.