In regexes, *
means "any number of the previous item", not "any number of any characters", like it does in shell patterns. And .
means "any single character".
So, to look for "anything, followed by literal .txt
", you'd use .*\.txt
. Or just \.txt
, since usually regex matches search for the match anywhere in the line. Then again \.txt
would also match a filename like foo.txtgz
, as the .txt
would not have to be at the end. You'd need \.txt$
to lock the pattern to the end of line.
The regex *.txt
is either meaningless, an error, or looks for a literal asterisk, depending on the implementation and if you're using basic regexes (grep
), or extended regexes (grep -E
). Best not to use it.
On the other hand, s*.txt
would look for "any number of letters s
, then any single character, then literal txt
". That's a more valid regex, but... still doesn't match sample.txt
.
Instead, what happens in your second command, is that because s*.txt
is not quoted, the shell expands the s*.txt
before grep
sees it. If the only matching file is sample.txt
, then grep
goes looking for that in the output of ls
. (If there were multiple matching filenames, the first would be taken as the pattern, and the rest as filenames for grep
to read. In that case, it'd ignore the input from the pipe.)
But, ls
can take a list of files too, so while you could use
ls | grep '\.txt'
to get any .txt
file, it'd probably be easier to just use
ls *.txt
instead.
*
), but they have different syntax and meanings. – Gordon Davisson Aug 14 '20 at 21:50grep
is for doingg/re/p
(i.e looking for a string that matches a regexp and printing the result) within files whilefind
is forfind
ing files (i.e. looking for files who match a given criteria including their name matching a globbing pattern). Btw - don't try to parse the output ofls
, see https://mywiki.wooledge.org/ParsingLs. – Ed Morton Aug 15 '20 at 03:47