-5

if i do ls the output is: enter image description here

but if i do ls | grep complex* or ll | grep complex* or even ll | grep * or ll | grep * | less the output is always: enter image description here

This is confusing to me.

I want to get a list of all files that start with complex* FYI if '*' == anything.

anishsane
  • 20,270
  • 5
  • 40
  • 73
hungryWolf
  • 391
  • 1
  • 3
  • 15
  • 2
    Because the shell expands `*`. If you want to get a list of all files that start with 'complex*' that'd be `ls complex*`. – n. m. could be an AI May 29 '16 at 04:42
  • Insert an `echo` to see what bash makes with your second command: `ls | echo grep *` – Cyrus May 29 '16 at 06:51
  • Worse, if `complex_assignment_other.c` file contains a line with phrase `complex_assignment.c`, (say `// this function is defined in file complex_assignment.c`) that line will be printed on terminal... – anishsane May 29 '16 at 06:52
  • @Cyrus, you can also educate OP about `set -vx`... – anishsane May 29 '16 at 06:54

4 Answers4

3

you're looking for:

ls | grep 'complex.*'

or, better:

ls complex*
webb
  • 4,180
  • 1
  • 17
  • 26
1

By default *is meant for [ globbing ].

If you have a file named * or one containing *, you could do

ls | grep \*

or

ls | grep '*'

If you are looking for literal * in the files you could do :

grep '*' *  # second will glob all the files in the current dir.

If you wish to use see all the files which have the word Complex_plus_something do:

grep -E '\<Complex[_[:alnum:]]+' *  

Here the + is for one or more and \< matches the empty string at the beginning of a word :-)

sjsam
  • 21,411
  • 5
  • 55
  • 102
1

To simplify my explanation, I won't speak of the hidden files.

Because your command doesn't mean what you're trying to achieve.

The * is very special for bash and doesn't have the meaning you think. It is a character the shell will replace with all the file names it can correspond to in the current directory. An example :

adrien@adrienLT:~/foo$ ls
adrien@adrienLT:~/foo$ touch foo
adrien@adrienLT:~/foo$ ls
foo
adrien@adrienLT:~/foo$ ls | grep *
foo

% The above is equivalent to $ ls | grep foo

adrien@adrienLT:~/foo$ touch bar
adrien@adrienLT:~/foo$ ls | grep *

% The above is equivalent to $ ls | grep bar foo, it will output something if the word "bar" is IN the file foo.

See there, an example with more files :

adrien@adrienLT:~/foo$ touch bar foo foobar
adrien@adrienLT:~/foo$ echo "bar" > foo
adrien@adrienLT:~/foo$ echo "bar" > foobar
adrien@adrienLT:~/foo$ ls | grep *
foo:bar
foobar:bar

Now, to do what you want to achieve, you can use * to your advantage :

adrien@adrienLT:~/foo$ ls foo*
foo  foobar

But if there is a directory that correspond your research, it will list its content.

adrien@adrienLT:~/foo$ mkdir foodir
adrien@adrienLT:~/foo$ for i in {0..10}; do touch "foodir/$i"; done
adrien@adrienLT:~/foo$ ls foo*
foo  foobar

foodir:
0  1  10  2  3  4  5  6  7  8  9

So you may want to use the option -d not to list their content :

adrien@adrienLT:~/foo$ ls -d foo*
foo  foobar  foodir

But if your search becomes more complicated, I can only advice to use a more powerful tool such as find.

This one uses globbing (the * I explained above)

adrien@adrienLT:~/foo$ find . -type f -name "foo*"
./foo
./foobar

This one uses regular expression but that is a tool you need to study a bit to be able to handle without loosing your hair :

adrien@adrienLT:~/foo$ find . -type f -regex ".*/foo[^/]*$"
./foo
./foobar

To explain a bit, the above search the current directory (.) for files only (-type f) which match a particular pattern (-regex "./foo[^/]$").

This pattern is "anything followed by slash foo followed by anything except slash until the end of the file".

Adrien Horgnies
  • 691
  • 4
  • 11
1

You have two mistakes: * doesn't mean "anything" in regular expressions, and because you didn't quote it, the shell expanded it.

If you have three files, the result of ls | grep * after wildcard expansion is something like

ls | grep bar baz foo

The behavior of grep in this situation is that it simply ignores standard input (this may not be documented and/or completely standard and/or well-defined), so ls | is ignored and useless. You end up looking for the name of the first matching file in the other two.

Now, the regular expression you used searches for comple anywhere in the input (x* means zero or more occurrences of x; if there are zero, the expression will match, and it doesn't prevent matching on, say, incomplete, so you might as way omit this). The correct expression is ^complex to find this word only at beginning of line (don't forget the quotes; ^ is also a shell metacharacter) or just complex to find it anywhere on a line.

If the point is just to enumerate, you don't need grep or regular expressions at all, or ls, either!

echo complex*

will show the names of all the matching files, or if you want one per line,

printf '%s\n' complex*

(This is also more robust, so generally a better approach. Avoid both ls and echo in scripts if you can.)

To loop over matching files, you cannot reliably use ls.

for f in complex*; do
    printf '%s\n' "$f"
done

As a special case, grep '*' looks for a literal asterisk. Some regex tools (rightfully) fail with an error message for invalid regex (including *BSD grep; the special case is in GNU grep).

tripleee
  • 175,061
  • 34
  • 275
  • 318