DaemonForums  

Go Back   DaemonForums > OpenBSD > OpenBSD General

OpenBSD General Other questions regarding OpenBSD which do not fit in any of the categories below.

Reply
 
Thread Tools Display Modes
  #1   (View Single Post)  
Old 10th January 2017
gustaf gustaf is offline
Fdisk Soldier
 
Join Date: Dec 2016
Posts: 69
Default OpenBSD find command -- exclude dot directory

How do I tell the OpenBSD find(1) command to exclude the dot directory, but not its contents, from the list of directories and files it generates?

It seems like this should be possible with the not (!) operator, but after searching the Web, reading (and re-reading) the find(1) man page, and trying out numerous combinations of arguments and operators, I still have not found a solution.

Using -prune doesn't work for me in this situation; -prune will cause find to not descend into the pruned directory. If the pruned directory is the dot directory, the contents of the directory will be missing. Effectively, find will generate an empty list. This is obviously not the desired behavior.

I have found ways to exclude:
  1. individual files plus the dot directory, or
  2. individual files and named directories,
but not all three types (the dot directory, named directories, and individual files) in the same command.

I've written a sample script to demonstrate the problem because it's easier to see than on the command line.

If, for example, my home directory is the current directory and contains the following items:

./
../
.Xdefaults
.cache/
.profile
dirA/
dirA/dirB/
dirA/dirB/file1
dirC/
dirC/file2
file3.txt
file4.pdf

and I want the generated list to look like this:

.profile
dirA/
dirA/dirB
dirA/dirB/file1
file3.txt

I can run this script to test the find command -- the results are explained in the comments:

Code:
#!/bin/sh
# findtest

cd $HOME

# Method 1 works to exclude the dot directory and specified files; 
# contents of named directories are ignored by find and end up in the printed list.
METHOD1='( 
            ! -name .
            ! -path ./.Xdefaults
            ! -path ./.cache
            ! -path ./dirC
            ! -path ./file4.pdf
         )'
find . $METHOD1 -print | sort > method1.txt

# Method 2 works to exclude named directories and specified files;
# adding the dot directory to this command results in an empty list.
METHOD2='(
            -path ./.Xdefaults -or
            -path ./.cache -or
            -path ./dirC -or
            -path ./file4.pdf
         )'
find . $METHOD2 -prune -or -print | sort > method2.txt

#Method 3 should exclude the dot directory, named directories, and specified files.
## METHOD3=...
## find . $METHOD3...
Is this an impossible task for OpenBSD find or have I just not figured out the logic?

Any help would be appreciated.

Last edited by gustaf; 11th January 2017 at 09:22 PM. Reason: added link to find(1) man page; corrected comments and code for Method 1
Reply With Quote
  #2   (View Single Post)  
Old 4th March 2017
kl3 kl3 is offline
New User
 
Join Date: Jan 2017
Posts: 7
Default

To exclude "the dot directory" (I assume you mean either of ./ ../) in general, tell find to always go one step down the hierarchy:
Code:
 $ find . -mindepth 1
.Xdefaults
.cache/
.profile
dirA/
dirA/dirB/
dirA/dirB/file1
dirC/
dirC/file2
file3.txt
file4.pdf
Exlcuding hidden directories but not their content:
Code:
$ find . ! \( -type d -name .\* \)
.Xdefaults
.profile
dirA/
dirA/dirB/
dirA/dirB/file1
dirC/
dirC/file2
file3.txt
file4.pdf
In order to omit arbitrary files or directories, just add the respective expressions to filter them out:
Code:
$ find . ! \( -type f \( -name .Xdefaults -o -name file4.pdf \) \) ! \( -type d -name dirC -prune \)
./
../
.cache/
.profile
dirA/
dirA/dirB/
dirA/dirB/file1
file3.txt
Combining all examples (the second one covers the first one, but still), you'll eventually get your desired list:
Code:
$ #find . -mindepth 1 ! \( -type d -name .\* \) ! \( -type f \( -name .Xdefaults -o -name file4.pdf \) \) ! \( -type d -name dirC -prune \) # Group negations
$ #find . -mindepth 1 ! \( \( -type d -name .\* \) -o \( -type f \( -name .Xdefaults -o -name file4.pdf \) \) -o \( -type d -name dirC -prune \) \) # Group types
$ find . -mindepth 1 ! \( \( -type d \( -name .\* -o \( -name dirC -prune \) \) \) -o \( -type f \( -name .Xdefaults -o -name file4.pdf \) \) \)
.cache/
.profile
dirA/
dirA/dirB/
dirA/dirB/file1
file3.txt
I expect this to be what you wanted in the end:
  1. Skip hidden directories themselves but not their content
  2. Skip certain individual files
  3. Skip certain directories entirely including their content

Node how the expressions regarding directories comes first to improve execution time. I'll leave the Why? up to you, the OPERATORS section in find(1) might be helpful.

Last edited by kl3; 5th March 2017 at 12:33 AM.
Reply With Quote
  #3   (View Single Post)  
Old 26th June 2017
gustaf gustaf is offline
Fdisk Soldier
 
Join Date: Dec 2016
Posts: 69
Default

After more searching and trial-and-error, I finally figured it out. I also realized that the original question didn't completely address the problem. I want to tell find(1) to generate a list of files and directories that:
  • includes everything in the current directory
  • EXCEPT
  • the directories and files specified in the command AND
  • the ./ directory
(The original post has the example directory to be searched and the search results.)

The find utility doesn't have a proper exclude argument for nested directories, so I had to use -prune with -path and -or to exclude directories and their contents:

Code:
find . \
     -path ./.Xdefaults -prune -or \
     -path ./.cache -prune -or \
     -path ./dirC -prune -or \
      ! -name file4.pdf -and \
      ! -name . \
     -print
Once I unlocked the mysteries of -prune, the problem became a lot less insurmountable:

According to the man page, find is by default recursive: "...find recursively descends the directory tree for each path listed..." (find(1), DESCRIPTION).

Using -prune "...causes find to not descend into the current file..." (find(1), PRIMARIES). That explains what -prune DOESN'T do, but what does -prune actually DO?

Re-phrased as a positive statement, -prune TURNS OFF RECURSION. It's that simple. When find encounters a pruned directory, it will skip over the entire contents of that directory and move on to the next top-level directory in the tree.

Excluding both the top-level directory and the directory's contents involves taking advantage of the side-effect of -prune combined with -or.

The GNU documentation for find (— Action: -prune) gives a detailed explanation of -prune:

Quote:
If the file is a directory, do not descend into it. The result is true. For example, to skip the directory src/emacs and all files and directories under it, and print the names of the other files found:
find . -wholename './src/emacs' -prune -o -print
The above command will not print ./src/emacs among its list of results. This however is not due to the effect of the '-prune' action (which only prevents further descent, it doesn't make sure we ignore that item). Instead, this effect is due to the use of '-o'. Since the left hand side of the 'or' condition has succeeded for ./src/emacs, it is not necessary to evaluate the right-hand-side ('-print') at all for this particular file...
Greg's Wiki also has a good explanation of why -prune is confusing and counterintuitive.

The POSIX documentation for find provides some additional examples.

Last edited by gustaf; 26th June 2017 at 05:17 AM. Reason: clarity
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
find last or special command I run with /bin/csh mfaridi FreeBSD General 6 10th January 2011 09:35 AM
HOWTO: Find Duplicated Files in Directory Tree vermaden Guides 22 27th April 2010 07:43 PM
Find command (Linux options?) deadeyes FreeBSD General 11 23rd August 2009 06:07 PM
exclude URL from caching at squid 3 ccc FreeBSD General 1 31st January 2009 06:20 PM
Command to find and replace, but not creating a new file 18Googol2 Programming 4 22nd September 2008 10:28 PM


All times are GMT. The time now is 02:42 AM.


Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Content copyright © 2007-2010, the authors
Daemon image copyright ©1988, Marshall Kirk McKusick