confused about usage of quotes and wildcards in linux
Hello everybody
I am struggling to learn command line in Linux and have noticed a confusing (at least for me ) behaviour of wildcards and quotting E.g : Code:
ioannis@ioannis-laptop:~$ locate *te* | wc -l And : Code:
ioannis@ioannis-laptop:~$ locate *arca* | wc -l Another case Code:
ioannis@ioannis-laptop:~/Music$ find -name '*th*' | wc -l So, is the behaviour of quotting and/or wildcards different depending on the command or am I missing something else ? Thanks in advance |
Quote:
Try the following program: Code:
#!/usr/bin/perl Code:
./args.pl *te* If you want the test program to print to stdout and not stderr as it does, replces 'warn' with 'print'. |
As you are using Ubuntu, you are more than likely running dash as a shell. This is quite similar to bash but with some different tweaks (none of which I think are affecting you here).
Sergei is quite right in saying that different applications / commands will have their own idiosyncrasies, but in this case I would say in all the situations where you have not quoted the string it is expanding to what it finds in the directory you are running in prior executing the command. Your first 2 examples are a good demonstration of this: Code:
ioannis@ioannis-laptop:~$ locate *te* | wc -l Hence if in the directory you have a file called: Code:
after Once quoted though, this now effectively passes the wildcards to locate and it performs its' own version of expansion as part of its' lookup. |
There are two levels of processing going on. First the shell processes the command line, then it passes it to the program, which does whatever it's designed to do.
In the locate example without quoting, the shell first tries to match files in the current directory and builds anything it matches into a list of filenames. This list is then passed to locate. Only if there are no matches does it pass the string on literally. Try running echo locate *te* and see what you get. Now lets look at what the locate man page says about how it processes the strings it gets: Code:
If a pattern is a plain string — it contains no metacharacters — locate displays The same thing is happening with find. The unprotected shell globbing is finding one match in the current directory for *th*, which when passed onto find is producing a syntax error due to the spaces in it. So the lesson learned is that you should nearly always quote strings when they contain anything other than plain text, and sometimes even then. :) |
Your shell (Bash, Dash, Sh, whatever) is expanding the unquoted wildcard character (*) before locate ever sees it.
A classic demonstration may be helpful. Try this on your own system and see what happens. Code:
$ mkdir junk locate is capable of expanding patterns, but if you don't quote your pattern then the shell will eat it first. The same happens with find --name Edit: A bit of related advice ... if you ever use regular expression from the command line, enclose the entire regex inside single quotes. Leaving a regex exposed to the shell is asking for all kinds of confusion. |
@grail
"say in all the situations where you have not quoted the string it is expanding to what it finds in the directory you are running in prior executing the command." I tested locate *te* and it gives me several results some of them in my home dir (where I run the command) and others outside it. A small sample is : Code:
/home/ioannis/Desktop/home_backup/ioannis/Templates When you quote or remove the wildcards then locate only has the information at hand to use, however, when using the unquoted wildcard version it first expands the string to whatever it finds locally. Hence if in the directory you have a file called: Code:
after It was very important for me to realize that different applications / commands will have their own idiosyncrasies and I should memorize some things instead of trying to solve all problems with logic as well as to understand that there are the 2 levels of processing as you describe Also , I think I have bash : Code:
ioannis@ioannis-laptop:~$ which bash |
Quote:
But .. Code:
ioannis@ioannis-laptop:~$ locate *te* | more -2 I have very little experience and please correct me if I am wrong but I start understanding that it doesnt make sense to try to understand how command line responds when you dont follow the rules |
Quote:
Thanks for your reply, I think the last part of your post is the most usefull In the And, I got "five one three" too. I wonder though to what could the * in *te* be expanded by the shell and only 29 results (all of them containing te though) but finally I understand the answer is not important |
Yes, it really is important!
Quote:
Code:
$ mkdir foo
Quote:
Code:
$ touch fake-mandb-file
The locate command without any options searches its entire database (the one maintained by updatedb). It is not restricted to your current directory. Code:
$ pwd
Quote:
Hope you're still reading, because here comes the most important part. Code:
$ locate *mandb*
I hope that now you can see why locate *te* might not return the same results as locate '*te*'. It is crucial to understand when Bash is eating your unquoted wildcard patterns and expanding them into unexpected strings of gibberish. Code:
$ locate '*mandb*' :cool: |
Quote:
I think it makes sense but just to make sure I understood this When giving the argument te , the bash searches for a file named exactly te, doesnt find any and it passes te unchanged to the command locate which in turn regards it as *te* because of the way locate works, searches its databese (created by updatedb) for *te* and finds a big number of matches since it looks for files containing te in their names When given as *te* , bash performs the pathname expansion, finds a few matches only, passes these expanded matches to the command locate which of course returns the same number of matches. So, it is clear why *te* gives different results than te . My only question is where does the bash search to find files And also : I understood that the quoted argument is not usefull with locate when looking in a specific directory |
Quote:
The rest of your paragraph is correct. Quote:
|
Quote:
But, something peculiar happens here : Now , when giving Code:
ioannis@ioannis-laptop:~$ locate *te* | wc -l In my comment nr 7 here, while I was getting only 29 results you see 2 of them ( there were more), not belonging to my home dir (in which I was while giving the command), so it appears that bash did not search only locally Any idea? |
Quote:
But, something peculiar happens here : Now , when giving Code:
ioannis@ioannis-laptop:~$ locate *te* | wc -l In my comment nr 7 here, while I was getting only 29 results you see 2 of them ( there were more), not belonging to my home dir (in which I was while giving the command), so it appears that bash did not search only locally Any idea? |
David the H. has it right
:hattip:
Quote:
Quote:
Code:
$ locate te
Quote:
Quote:
Code:
~$ mkdir foo
Quote:
Code:
~/foo$ mkdir bar Quote:
Quote:
I suppose it is also conceivable that your system is configured somewhat differently with regards to locate and/or shell options. I can't even guess what those differences might be. In such a case you will have to review the appropriate documentation and configuration files with great intensity to discover the cause. I very much doubt this is the case though. |
Thanks again for your detailed reply
I have made clear in my mind that bash intervenes only to do the globbing and that if no globbing is required, it passes the arguments to locate. Bash compares strings with unquoted pattern matching characters against the names of files in the current working directory. As David the H. correctly pointed out, Bash also obeys any relative paths you specify like ./subdir/ or ../otherdir/ when matching the pattern. Code:
~/foo$ mkdir bar I presume this is what should happen and indeed, when giving e.g Code:
ioannis@ioannis-laptop:~/Music$ locate *th* | wc -l I can't really say because I don't know your system. My best guess is that no files in your current working directory match the pattern, so locate receives the argument *te*. No , it cant be the case because I didnt change anything .Something really strange ins going on : Code:
ioannis@ioannis-laptop:~$ mkdir kate And only about the half belong to my home dir : Code:
ioannis@ioannis-laptop:~$ locate *te* | tail -2 I suppose it is also conceivable that your system is configured somewhat differently with regards to locate and/or shell options. I can't even guess what those differences might be. In such a case you will have to review the appropriate documentation and configuration files with great intensity to discover the cause. I very much doubt this is the case though.[/QUOTE] I have a clean installation of Ubuntu 10.10 64 bit and have touched nothing related to configurations of bash . I suspect that a bug is a possibility here |
All times are GMT -5. The time now is 12:55 AM. |