I am iterating over files like so:
find $directory -type f -exec codesign {} \;
Now the problem here is that files on a higher hierarchy are signed first. Is there a way to iterate over a directory tree and handle the deepest files first?
So that
/My/path/to/app/bin
is handled before
/My/path/mainbin
CodePudding user response:
Yes, just use -depth
:
-depth
The primary shall always evaluate as true; it shall cause descent of the directory hierarchy to be done so that all entries in a directory are acted on before the directory itself. If a -depth primary is not specified, all entries in a directory shall be acted on after the directory itself. If any -depth primary is specified, it shall apply to the entire expression even if the -depth primary would not normally be evaluated.
For example:
$ mkdir -p top/a/b/c/d/e/f/g/h
$ find top -print
top
top/a
top/a/b
top/a/b/c
top/a/b/c/d
top/a/b/c/d/e
top/a/b/c/d/e/f
top/a/b/c/d/e/f/g
top/a/b/c/d/e/f/g/h
$ find top -depth -print
top/a/b/c/d/e/f/g/h
top/a/b/c/d/e/f/g
top/a/b/c/d/e/f
top/a/b/c/d/e
top/a/b/c/d
top/a/b/c
top/a/b
top/a
top
Note that at a particular level, ordering is still arbitrary.
CodePudding user response:
Using GNU utilities, and decorate-sort-undecorate pattern (aka Schwartzian transform):
find . -type f -printf '%d %p\0' |
sort -znr |
sed -z 's/[0-9]* //' |
xargs -0 -I@ echo codesign @
Drop the echo
if the output looks ok.
CodePudding user response:
How about sorting the output of find
in descending order:
while IFS= read -d "" -r f; do
codesign "$f"
done < <(find "$directory" -type f -print0 | sort -zr)
<(command ..)
is a process substitution which feeds the output of thecommand
to theread
command inwhile
loop via the redirect.-print0
,sort -z
andread -d ""
combo uses a null character as a file delimiter. It is useful to protect filenames which include special characters such as whitespace.
CodePudding user response:
I don't know if there is a native way in find
, but you may pipe the output of it into a loop and process it line by line as you wish this way:
find . | while read file; do echo filename: "$file"; done
In your case, if you are happy just reversing the output of find
, you may go with something like:
find $directory -type f | tac | while read file; do codesign "$file"; done
CodePudding user response:
If I understand correctly, you want /My/path/mainbin
to be processed after /My/path/to/app/bin
.
find
doesn't have an option for that but you can specify its arguments in the order that you need, so, in combination with bash you could do:
#!/bin/bash
shopt -s extglob
find /My/path/!(mainbin) /My/path/mainbin -type f -exec codesign {} \;
That will ensure that mainbin
is the last one to be processed
CodePudding user response:
Using find
's -depth
option as my other answer, or naive sort as some others, only ensures that sub-directories of a directory are processed before the directory itself, but not that the deepest level is processed first.
For example:
$ mkdir -p top/a/b top/a/c/d
$ find top -depth -print
top/a/c
top/a/b/d
top/a/b
top/a
top
For overall deepest level to be processed first, the ordering should be something like:
top/a/b/d
top/a/c
top/a/b
top/a
top
To determine this ordering, the entire list must be known, and then the number of levels (ie. /
) of each path counted to enable ranking.
A simple-ish Perl script (assigned to a shell function for this example) to do this ordering is:
$ dsort(){
perl -ne '
BEGIN { $/ = "\0" } # null-delimited i/o
$fname[$.] = $_;
$depth[$.] = tr|/||;
END {
print
map { $fname[$_] }
sort { $depth[$b] <=> $depth[$a] }
keys @fname
}
'
}
Then:
$ find top -print0 | dsort | xargs -0 -I@ echo @
top/a/b/d
top/a/c
top/a/b
top/a
top