Hacker News new | ask | show | jobs
by hnlmorg 3203 days ago
Some handy tips there but I would recommend changing some of the `find` examples:

    find . -exec echo {} \;      # One file by line
You don't need to execute echo to do that as find will output by default anyway. There is also a `-print` flag if you wish to force `find` to output.

    find . -exec echo {} \+      # All in the same line
This is think is a dangerous example because any files with spaces will look like two files instead of one delimited by space.

Lastly, in both the above examples you're returning files and directories rather than just files. If you wanted to exclude directories then use the `-type f` flag to specify files:

    find . -type f ...
(equally you could specify only directories with `-type d`)

Other `find` tips I've found useful that might be worth adding:

* You don't need to specify the source directory in GNU find (you do on FreeBSD et al) so if you're lazy then `find` will default to your working directory:

    find -type f -name "*.txt"
* You can do case insensitive named matches with `-iname` (this is also GNU specific):

    find -type f -iname "invoice*"
3 comments

> * You can do case insensitive named matches with `-iname` (this is also GNU specific): > > find -type f -iname "invoice*"

This was added to OpenBSD 17 years ago. Other BSDs soon followed. Solaris & IllumOS support it too.

http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/find/op...

For some reason I recalled -iname failing on FreeBSD but I've just logged onto some devs boxes (not that I didn't trust your post!) and it seems you're right as the option is there in the man pages.

Apologies for this. It just goes to show how fallible the human memory is. :-/

Another option instead of 'find' in BASH is the globstar option. If set then pathname expansion will include zero or more subdirectories:

  ls **/*.c
Results in something like:

  array.c                   helpers/gendec.c         msg.c
  awkgram.c                 helpers/mb_cur_max.c     node.c
  awklib/eg/lib/grcat.c     helpers/scanfmt.c        old-extension/bindarr.c
Turn on with:

  shopt -s globstar
The only forbidden characters in a Unix filenames are '/' and '\0'

Want to mess with such a script?

$ touch "$(echo -e -n 'lol\nposix')"

One of the cruelest things you can do is a filename that consists only of a combining diacritic (without a glyph that it could combine with). Will break outputs of various programs (starting with ls) in sometimes hilarious ways.

If you're trying it out now and cannot figure out how to delete it: "ls -li" to find the file's inode number, then `find -inum $INODE_NUMBER -delete`.

Wow, that's really horrible. I have a file sitting around with a couple of newlines in the name just so I can see how many programs don't cope with it, but I hadn't thought of using a lone combining diacritic.

If anyone wants a command to make one, try

    touch $'\U035F'
(using U+035F COMBINING DOUBLE MACRON BELOW for no particular reason, see [1] for more)

[1]: https://en.wikipedia.org/wiki/Combining_Diacritical_Marks

Indeed. This is one of the reasons why I wrote a shell that handles file names as JSON strings.

However for normal day to day usage, file names with \n are rare while files with spaces in their name are common. So returning an array of space delimited file names is a potentially dangerous practice for common scenarios where as find's default behaviour is only dangerous for weird and uncommon edge cases. (And if you think those are a likely issue then you probably shouldn't be doing your file handling inside a POSIX shell in the first place).