peterchen932
peterchen932

Reputation: 113

why the ls -R (recursing down) doesn't work with regular expression

In my case, the directory tree is following

[peter@CentOS6 a]$ tree  
.  
├── 2.txt  
└── b  
    └── 1.txt

1 directory, 2 files

why the following two command does only get 2.txt?

[peter@CentOS6 a]$ ls -R *.txt
2.txt
[peter@CentOS6 a]$ ls -R | grep *.txt
2.txt

Upvotes: 2

Views: 179

Answers (4)

hymie
hymie

Reputation: 2068

The other problem that nobody has mentioned yet is that, beyond the fact that the shell intercepts the * before grep sees it, the shell treats * differently from grep.

The shell uses file globbing, and * means "any number of characters".

grep uses regular expressions, and * means "any number of the preceding item".

What you need to do is

ls -R | grep .\*\\.txt

which will

  • escape the * so your shell does not intercept it
  • properly format the regular expression the way grep expects
  • properly escape the . in .txt to ensure that you have file extensions

Upvotes: 1

v010dya
v010dya

Reputation: 5858

It isn't clear if you are asking "why" meaning "explain the output" or "how should it be done". Steephen has already answered the latter, this is an answer to the former.

The reason for that is called "shell expansion". When you type *.txt in the command line, the program doesn't get it as a parameter, but rather the shell expands it and then passes the results.

*.txt expands to be "all files in the current directory with arbitrarily many symbols in the beginning, ending with '.txt' and not starting with '.'".

This means that when you type "ls -R *.txt" the command that actually executes is "ls -R 2.txt"; and when you do "ls -R | grep *.txt" it actually executes "ls -R | grep 2.txt".

This is the exact reason why Steephen has put quotation marks around the wildcard in the answer provided. It is necessary to stop this expansion. In fact you could also do so with single quotes or by placing a slash before any special character. Thus any of the following will work:

find . -name "*.txt"

or

find . -name '*.txt'

or

find . -name \*.txt

Upvotes: 1

nneonneo
nneonneo

Reputation: 179592

In both cases, your shell is expanding *.txt into 2.txt before the argument hits the command. So, you are in effect running

ls -R 2.txt
ls -R | grep 2.txt

You can't tell ls to look for a file pattern - that's what find is for. In the second case, you should quote your expression and use a proper regex:

ls -R | grep '\.txt'

Upvotes: 3

Steephen
Steephen

Reputation: 15824

You can use find as follows to list all matching files in current and sub directories

find . -name "*.txt"

Upvotes: 2

Related Questions