82

I have not found a reason why Mac's find does not have the option -printf. Apple normally decides to take options out which are not orthogonal to the other commands?

How can you reach the same result as the following command in Mac without coreutils?

find . -printf "%i \n" // command in Ubuntu 
2
  • what is the expected output from the command? Commented Jul 26, 2022 at 17:04
  • Confused about why %i (inode number) was used as an example when ls -Ri would seem to be the preferred tool for the job there, and about the trailing space before the newline. Could the OP chime in on that? Commented Feb 28, 2023 at 20:42

6 Answers 6

73

It's not that Apple removes options, it's that OS X's UNIX underpinnings are mostly derived (circuitously) from FreeBSD, many parts of which can be traced back to the original UNIX... as opposed to the GNU utilities, which are re-implementations with many features added.

In this case, FreeBSD's find(1) doesn't support -printf, so I wouldn't expect OS X's to either. Instead, this should work on a BSD-ish system:

find . -print0 | xargs -0 stat -f '%i ' 

It'll fail on a GNU-userland system, though, where you'd write xargs -0 -r stat -c '%i ' because xargs(1) and stat(1) behavior is different.

Sign up to request clarification or add additional context in comments.

7 Comments

For some reason this prints numbers instead of strings in iTerm2 on OS X 10.8.4. Instead, gfind from the indutils package of MacPorts suggested by dmckee works fine.
That's because %i prints the inode.
@TylerA. how to print file names instead of numbers?
@mesqueeb man stat gives you the different format values. it looks like replacing %i with %N will give you the file name, e.g. find . -print0 | xargs -0 stat -f '%N '
%N prints file full path, what if I only want file's basename?
|
58

MacOS find binary does not support the -printf argument.

gfind supports -printf option, it can be installed using brew install findutils

1 Comment

This also works for FreeBSD and FreeBSD Jails. Thanks.
24

Well, ephemient and bendin nailed the cause.

I'd add that there is nothing stopping you from installing GNU find (from the findutils) if you need it. If you use fink there is a findutils package. MacPorts has it too.

2 Comments

You can install it with Homebrew as well: brew install findutils Use gfind instead of find then.
@3zzy Does your path include the GNU version? Does it come before or after the system version? Using gfind may force using the GNU version.
8

Alternatively, you could just

find . -type f -exec stat -f "%z %N" {} \; 

Granted, this isn't how you would do the same thing on linux, but works for MacOS

find . -type f -exec stat -c "%s %N" {} \; 

produces similar (not same, but close) output on linux.

2 Comments

what's the -type and -exec stat stand for??
@mesqueeb in a terminal type man find, then you'll be looking at a man page within the pager program called less; hit / to start a search, and search for those options. While searching, n advances to the next occurrence of the search term, while the capital N goes back to the previous occurrence.
4

Ubuntu ships with the GNU version of find, which is more featureful than Mac OS X's find, which is of BSD lineage.

In fact, most of the Ubuntu's user-land utilities are from the GNU project. (Thus you'll sometimes hear Linux-based systems referred to as "GNU/Linux".)

Comments

0

Maybe it's worth noting that

ls -Ri | awk '{print $1}' 

does effectively the same thing as the OP's example, on all platforms in question. I get that -printf "%i \n" may have just been a generic "for instance," though.

If you need a solution that is relatively certain to work in both GNU and BSD-ish environments, you can define a function which handles the underlying implementation details. However, this gets gnarly quick (as you'll see), and you have to start accounting for things like how to use xargs -I{} and still accommodate filenames with whitespace.

But if you're up for all that:

stat_inode_number() { if [ "$(uname -s)" = "Linux" ]; then # not sure if OP's trailing space was intentional, but keeping it here stat -c '%i ' "$@" else stat -f '%i ' "$@" fi } # export function to subshells, e.g., pipes export -f stat_inode_number find . -print0 | xargs -I{} -0 sh -c "stat_inode_number '{}'" 

To briefly answer Bruce Sun's question from above, of what to do if the existing stat formats don't suit your needs: you're either in basename territory at that point, or you need to look into Bash parameter expansion (e.g., ${var##*/}), both of which are beyond the scope here.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.