8

Why does ls --ignore not ignoring the pattern?

Looking at the below example:

mkdir books
cd books
touch books_abby.csv
touch books_karen.csv
touch books_david.csv
touch books_tom.csv

This creates four files:

$ ls
books_abby.csv  books_david.csv  books_karen.csv  books_tom.csv

If however you want to ignore all filename containing "tom" and list them, books_tom.csv is still returned:

$ ls *.csv --ignore="*tom*"
books_abby.csv  books_david.csv  books_karen.csv  books_tom.csv

The expected outcome is for files containing "tom" to be omitted:

$ ls *.csv --ignore="*tom*"
books_abby.csv  books_david.csv  books_karen.csv

1 Answer 1

12

The flag is described in the ls man page like so (emphasis is mine) ...

do not list implied entries matching shell PATTERN

The man page doesn't have much to say about "implied" so what the heck does it mean? An implied entry (file, directory, etc.) is an entry that ls will return without you having explicitly provided an argument that matches that entry. A match can either be the actual name of the entry (ls books_tom.csv ... using your example) or a glob that matches it (ls *tom.csv, for instance).

Taking this to its logical limit, if you call ls with no arguments everything that is returned is implied! I'm assuming that the most common use of --ignore is with such an otherwise unadorned ls call because it is the easiest way to do a "list everything but X" operation...at least if you want to avoid using any other commands.

So, let's look at your command. With ls *.csv --ignore="*tom*" "books_tom.csv" is explicitly referenced by way of the matching pattern *.csv. With ls --ignore="*tom*", per the previous paragraph, everything in the directory is implied thus "books_tom.csv" will not be displayed.

If you have extended globbing available in your shell (with bash you can enable with shopt -s extglob) you can achieve what you want by crafting a pattern that will exclude 'tom'. For example ls books_!(tom).csv would show books_abby.csv but not books_tom.csv.

(Of course, you can use other tools like find, pipe to grep -v, etc...I'm just giving a pure ls solution.)

5
  • Is there a way to achieve the desired behaviour without grep?
    – Greg
    Oct 29, 2017 at 9:22
  • I've tried the ls books_!(tom).csv solution and it works :) My actual use case has dates in the filenames (e.g. 2017_10_29) and I am trying to get a list of all files without the date using ls *_!(2017_10_29).csv and ls *_!("2017_10_29").csv however it still returns files from that date, any idea why?
    – Greg
    Oct 29, 2017 at 9:49
  • Yes, because books_2017_ matches the *_ and 10_29.csv matches !(2017_10_29).csv. If you use books_!(2017_10_29).csv that would work. It's better if you use more explicit patterns because * is very flexible.
    – B Layer
    Oct 29, 2017 at 9:55
  • 3
    @Greg it really sounds like you should be using find (e.g. find . -name '*csv' -not -name '*2017_10_29*') or, assuming your file names have no whitespace or other strange characters, just ls *csv | grep -v 2017_10_29.
    – terdon
    Oct 29, 2017 at 9:57
  • @terdon Thank you, that approach is actually everything I was looking for
    – Greg
    Oct 29, 2017 at 9:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .