14

The ls can give a result like

[root@localhost ~]# cd /etc/yum.repos.d/
[root@localhost yum.repos.d]# ls

CentOS-Base.repo CentOS-Debuginfo.repo CentOS-Media.repo CentOS-Vault.repo

But actually I hope to just find out CentOS-Base.repoCentOS-Debuginfo.repo and CentOS-Vault.repo but not CentOS-Media.repo. So I run this command

ls [^\(Media\)]

But I get a error information.How should I do?

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
yode
  • 1,037
  • 4
  • 11
  • 19
  • Related: [Exclude one pattern from glob match](https://unix.stackexchange.com/questions/164025/exclude-one-pattern-from-glob-match) – steeldriver Jun 23 '17 at 11:55
  • @steeldriver Thanks for your link,that is very usefull for me.. – yode Jun 23 '17 at 12:07
  • You might consider switching your shell to [zsh](http://zsh.org/), which has a [pattern removal](http://zsh.sourceforge.net/Guide/zshguide05.html#subst) facility – Basile Starynkevitch Jul 02 '17 at 15:19

4 Answers4

12

A few shells have negation globbing operators:

  • zsh -o extendedglob:

    ls -d -- ^*Media*
    ls -d -- *.repo~*Media* # ~ is "except" operator
    
  • ksh, zsh -o kshglob, bash -O extglob:

    ls -d -- !(*Media*)
    
  • bash:

    GLOBIGNORE='*Media*'
    ls -d -- *
    
  • ksh:

    FIGNORE='@(*Media|.)*'
    ls -d -- *
    
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
11

In most simple case you may use the following (in case if the 1st subword is static CentOS):

ls CentOS-[BDV]*

  • [BDV] - character class to ensure the second subword starting with one of the specified characters

or the same with negation:

ls CentOS-[^M]*

If you want to ignore all filenames that contain the M character, with the GNU implementation of ls (as typically found on CentOS), use the -I (--ignore) option:

ls -I '*M*'

-I, --ignore=PATTERN
do not list implied entries matching shell PATTERN

To ignore entries with Media word:

ls -I '*Media*'

Those patterns need to be passed verbatim to ls, so must be quoted (otherwise, the shell would treat them as globs to expand).

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
RomanPerekhrest
  • 29,703
  • 3
  • 43
  • 67
  • Why we cannot use `ls *[^M]*`? – yode Jun 23 '17 at 12:00
  • The `ls CentOS-[^M]*` work,but the `ls *[^M]*` don't.. – yode Jun 23 '17 at 12:07
  • @yode, depends on what exactly you want to ignore: `M` character occurence OR `Media` word? – RomanPerekhrest Jun 23 '17 at 12:10
  • But in my case,only that file have a charater `M`. – yode Jun 23 '17 at 12:11
  • @yode, see my notation in the answer – RomanPerekhrest Jun 23 '17 at 12:17
  • Thanks your answer very very much,though I think the `ls *[^M]*` should work here still. – yode Jun 23 '17 at 12:38
  • 3
    The patterns are greedy: the first * matches everything except the last letter, the [^M] matches the last letter since none of them ends with M and the trailing * matches the empty string. So they all match. And even if something ended with M, it would still match, assuming there was something different from M somewhere: e.g. if you had a file called OOM, the first star would match the first O, the [^M] would match the second O and the trailing start would match the M. – NickD Jun 23 '17 at 12:49
8

The easiest way is to use find. Do:

find . -maxdepth 1 -type f ! -name "CentOS-Media.repo"

Here "f" means search for regular files only (excludes symlinks to regular files though; with GNU find, use -xtype f instead to include them). If you want to search for directories, pass "d" instead.

(-maxdepth while initially a GNU extension is now quite common. If your find doesn't support it, you can replace -maxdepth 1 with the standard ! -name . -prune).

see the find man page for more awesome features.

Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
user224532
  • 79
  • 2
6

One option is to use find with the -not -name flags. I.e. find . -not -name CentOS-Media.repo. If you don't want to recurse down the directory structure, add -maxdepth 1 flag.

Alternatively, one may write the following (which is much more complex, but I forgot about -not flag and posted this answer originally, so I will not delete this part):

find . -print0 | grep --invert-match -z "CentOS-Media.repo$" | tr '\0' '\n'

You need to force find to separate filenames with null byte, so that newlines in filenames won't break anything down. Hopefully, grep supports this kind of separator with flag -z. You may want to revert to the typical separation (i.e. null byte -> new line) with tr '\0' '\n'

styrofoam fly
  • 512
  • 6
  • 13
  • 1
    You can also get null-separated filenames with `printf '%s\0' *` which doesn't recurse and doesn't include dotfiles by default (but some shells have an option for that). You also don't need `-E` for _that_ regexp, but to be picky you should either backslash the `.` or put it in `[]`, and you do depend on _GNU_ find and grep. – dave_thompson_085 Jun 23 '17 at 18:10