View previous topic :: View next topic |
Author |
Message |
gsoe Apprentice
Joined: 10 Dec 2006 Posts: 289 Location: Denmark
|
Posted: Tue Mar 19, 2013 1:33 pm Post subject: Strange behaviuor of "find" [SOLVED] |
|
|
Hi!
After 10 years using linux I still happen to stumble upon things that baffle me.
Can anyone explain this behaviuor:
Code: | serv2 ~ # ls /etc | grep ^env
env.d
environment
serv2 ~ # find /etc -name env*
/etc/environment
/etc/env.d
|
But then: Code: | serv2 ~ # ls /etc | grep gru
grub.d
serv2 ~ # find /etc -name grub*
serv2 ~ # find /etc -name 'grub*'
/etc/grub.d
/etc/default/grub
/etc/portage/package.keywords/grub
|
Greetings gsoe
Last edited by gsoe on Tue Mar 19, 2013 3:53 pm; edited 1 time in total |
|
Back to top |
|
|
gsoe Apprentice
Joined: 10 Dec 2006 Posts: 289 Location: Denmark
|
Posted: Tue Mar 19, 2013 1:59 pm Post subject: |
|
|
The plot thickens: Code: | serv2 ~ # find /etc -name grub*
serv2 ~ # cd /etc/
serv2 etc # find /etc -name grub*
/etc/grub.d
serv2 etc # find /etc -name 'grub*'
/etc/grub.d
/etc/default/grub
/etc/portage/package.keywords/grub
serv2 etc #
|
|
|
Back to top |
|
|
eyoung100 Veteran
Joined: 23 Jan 2004 Posts: 1428
|
Posted: Tue Mar 19, 2013 2:08 pm Post subject: |
|
|
It might help you get the answer you expect if you were to add the trailing /
Code: | ls etc | grep gru
find /etc/ grub* |
From the find man page:
Quote: | -name pattern
Base of file name (the path with the leading directories removed) matches shell pattern pattern. The metacharacters ('*', '?', and '[]') match a '.' at the start of the base name (this is a change in findutils-4.2.2; see section STANDARDS CONFORMANCE below). To ignore a directory and the files under it, use -prune; see an example in the description of -path. Braces are not recognised as being special, despite the fact that some shells including Bash imbue braces with a special meaning in shell patterns. The filename matching is performed with the use of the fnmatch(3) library function. Don't forget to enclose the pattern in quotes in order to protect it from expansion by the shell. |
GNU Grep 2.14
GNU Find _________________ The Birth and Growth of Science is the Death and Atrophy of Art -- Unknown
Registerd Linux User #363735
Adopt a Post | Strip Comments| Emerge Wrapper
Last edited by eyoung100 on Tue Mar 19, 2013 2:19 pm; edited 1 time in total |
|
Back to top |
|
|
gsoe Apprentice
Joined: 10 Dec 2006 Posts: 289 Location: Denmark
|
Posted: Tue Mar 19, 2013 2:19 pm Post subject: |
|
|
The trailing slash doesn't seem to make any difference: Code: | serv2 ~ # find /etc/ -name grub*
serv2 ~ # find /etc/ -name 'grub*'
/etc/grub.d
/etc/default/grub
/etc/portage/package.keywords/grub
serv2 ~ #
| Omitting the "-name" option Code: | serv2 ~ # find /etc/ grub*
| just returns hundreds of false positives, in fact about everything in /etc. |
|
Back to top |
|
|
py-ro Veteran
Joined: 24 Sep 2002 Posts: 1734 Location: Velbert
|
Posted: Tue Mar 19, 2013 3:06 pm Post subject: |
|
|
if you write the * will be interpreted by your shell. |
|
Back to top |
|
|
gsoe Apprentice
Joined: 10 Dec 2006 Posts: 289 Location: Denmark
|
Posted: Tue Mar 19, 2013 3:16 pm Post subject: |
|
|
Hi py-ro!
I see. So in the case of Code: | find /etc -name 'foo*' | the "find" command will interpret the expression?
But then again, why do Code: | serv2 ~ # find /etc -name grub*
serv2 ~ # find /etc -name env*
/etc/environment
/etc/env.d
serv2 ~ #
| behave differently? A shell problem?
Greetings gsoe. |
|
Back to top |
|
|
py-ro Veteran
Joined: 24 Sep 2002 Posts: 1734 Location: Velbert
|
Posted: Tue Mar 19, 2013 3:23 pm Post subject: |
|
|
You can view which expand it will do.
Position your cursor after env* and press atleast in Basc. |
|
Back to top |
|
|
gsoe Apprentice
Joined: 10 Dec 2006 Posts: 289 Location: Denmark
|
Posted: Tue Mar 19, 2013 3:50 pm Post subject: |
|
|
Hi py-ro and eyoung100
Thanks for the pointer to the man excerpt and the bit about the shell expansion. Nifty little trick. I get the expected results, when my cwd is /etc: Code: | serv2 etc # grub*
grub.d/
serv2 etc # env*
env.d/ environment | But apparently something about letting the shell expand expressions for find is confusing the find command: Code: | serv2 etc # find /etc -name gru*
/etc/grub.d
serv2 etc # find /etc -name env*
find: paths must precede expression: environment
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
serv2 etc # find /etc -name envi*
/etc/environment
serv2 etc # | I'll regard the subject as solved and abandon my former sloppy use of find.
Greetings gsoe |
|
Back to top |
|
|
khayyam Watchman
Joined: 07 Jun 2012 Posts: 6227 Location: Room 101
|
Posted: Tue Mar 19, 2013 5:11 pm Post subject: |
|
|
gsoe wrote: | But apparently something about letting the shell expand expressions for find is confusing the find command |
gsoe ... find expects '-name' to be a pattern, eg, 'pat*', but if its expanded by the shell it becomes multiple 'pat patter patterns'. The 'find' manpage states "[p]lease note that you should quote patterns as a matter of course, otherwise the shell will expand any wildcard characters in them." So, its not really confused, it just expects 'pat*' to be a pattern and not a string of space delimited words.
best ... khay |
|
Back to top |
|
|
gsoe Apprentice
Joined: 10 Dec 2006 Posts: 289 Location: Denmark
|
Posted: Tue Mar 19, 2013 5:36 pm Post subject: |
|
|
Hi khay
Thank you for the elaboration. So really Code: | serv2 etc # find /etc -name env*
find: paths must precede expression: environment
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression] | doesn't work because the shell expansion returns a string of space delimited words, namely while Code: | serv2 etc # find /etc -name envi*
/etc/environment | does work because there's only one instance of a word in the expansion.
I have to admit that when I read the "-name" section in the man pages years ago, I must have memorised something like like "omit the quotes if it works without them". Luckily I haven't run into any disasters because of it!
Greetings gsoe. |
|
Back to top |
|
|
khayyam Watchman
Joined: 07 Jun 2012 Posts: 6227 Location: Room 101
|
Posted: Tue Mar 19, 2013 7:36 pm Post subject: |
|
|
gsoe ...
yes, so its like passing a sentence rather than a pattern. It really just depends on how the shell treats meta characters.
Code: | # echo $SHELL
/bin/zsh
# find /etc -name env{*}
/etc/environment
/etc/env.d
/etc/portage/env
# print -rl /etc/**/env*
/etc/env.d
/etc/environment
/etc/portage/env |
best ... khay |
|
Back to top |
|
|
Akkara Bodhisattva
Joined: 28 Mar 2006 Posts: 6702 Location: &akkara
|
Posted: Tue Mar 19, 2013 8:23 pm Post subject: |
|
|
gsoe wrote: | So really find /etc -name env* doesn't work because the shell expansion returns a string of space delimited words ... while find /etc -name envi* does work because there's only one instance of a word in the expansion. |
That's correct.
Best usage for find is to always include quotes in patterns, that way you're not relying on the luck of directory contents as to whether it works or not. Also, (in case you weren't aware), there's a difference between single quotes and double quotes. Check the documentation or ask here if you need that cleared up.
Also: omission of quotes exposes a possible vulnerability if the directory is world-writable that someone could stick extra files in there just to mess this up. Alas there's a lot of these sorts of hiccups in shell. It's easy to get started and write something quick but it's a lot harder to make sure all pathological cases are adequately covered.
Oh, one final thought/trick: Put echo in front of a command line to see what the command that gets issued looks like after the shell's done it's magic. As in, echo find /etc -name env*. _________________ Many think that Dilbert is a comic. Unfortunately it is a documentary. |
|
Back to top |
|
|
gsoe Apprentice
Joined: 10 Dec 2006 Posts: 289 Location: Denmark
|
Posted: Tue Mar 19, 2013 8:59 pm Post subject: |
|
|
Hi again
Quote: | Best usage for find is to always include quotes in patterns | That's exactly my conclusion! I've just realised the reason for some of the behaviour was: Quote: | the luck of directory contents as to whether it works or not | It also seems that cached contents of the shell has some influence on what happens.
@khay; I've noticed that some experienced users (while hardly any inexperienced) use zsh. Maybe time has come to look into it.
Thanks again! gsoe |
|
Back to top |
|
|
khayyam Watchman
Joined: 07 Jun 2012 Posts: 6227 Location: Room 101
|
Posted: Tue Mar 19, 2013 10:27 pm Post subject: |
|
|
gsoe wrote: | @khay; I've noticed that some experienced users (while hardly any inexperienced) use zsh. Maybe time has come to look into it. |
gsoe ... well, zsh is a 'bourne' shell, and though it uses some ksh idioms, there is nothing that would cause a bash user to wonder ... if you switched tommorow you probably wouldn't notice the difference.
Its not *just* for experienced users :) ... there are just many interactive features that make it a pleasure to use, eg,
Code: | # for i (*.txt) mv $i ${i/.txt/.sh}
# zmv '(*).sh' '$1.txt' |
In the former the 'for i in <condition> ; do <command> ; done' is simplified, and the latter is just a better way to do the former .... and reverses it :)
See:
A User's Guide to the Z-Shell
The Zshell Guide
Zsh Documentation
zsh-lovers (app-shells/zsh-lovers)
best ... khay |
|
Back to top |
|
|
eyoung100 Veteran
Joined: 23 Jan 2004 Posts: 1428
|
Posted: Tue Mar 19, 2013 10:37 pm Post subject: |
|
|
just a hunch that last script takes all the files ending in .txt and renames them to files ending in sh, and thats a lot easier to read _________________ The Birth and Growth of Science is the Death and Atrophy of Art -- Unknown
Registerd Linux User #363735
Adopt a Post | Strip Comments| Emerge Wrapper |
|
Back to top |
|
|
gsoe Apprentice
Joined: 10 Dec 2006 Posts: 289 Location: Denmark
|
Posted: Tue Mar 19, 2013 10:53 pm Post subject: |
|
|
I see. Some extended commands that'll make life easier, if you really use your shell. If you don't know them well, the bash way might be easier to understand.
Greetings. gsoe |
|
Back to top |
|
|
khayyam Watchman
Joined: 07 Jun 2012 Posts: 6227 Location: Room 101
|
Posted: Tue Mar 19, 2013 11:09 pm Post subject: |
|
|
eyoung100 wrote: | just a hunch that last script takes all the files ending in .txt and renames them to files ending in sh, and thats a lot easier to read 8) |
eyoung100 ... yes, thats what the first command, the 'for', does, and the second 'zmv' reverses the the outcome of the previous command.
gsoe wrote: | Some extended commands that'll make life easier, if you really use your shell. If you don't know them well, the bash way might be easier to understand. |
gsoe ... I don't see that at all ... there is 'familarity' involved whether it is bash or zsh.
best ... khay |
|
Back to top |
|
|
gsoe Apprentice
Joined: 10 Dec 2006 Posts: 289 Location: Denmark
|
Posted: Tue Mar 19, 2013 11:22 pm Post subject: |
|
|
Well, yes I guess so. The first one I could immediately understand by familiarity with bash , the second one I wouldn't have guessed without seeing the first. Anyhow, as soon as you've seen the "zmv" command once, you probably won't forget it again.
As for myself, it may be harder to remember the syntax of the bash "for i in... do... done" command. Whenever I use it, I always make it do something innocent like "echo" the result. Just to make sure...
Greetings gsoe |
|
Back to top |
|
|
|