4

I am trying to find all symlinks below current folder whose target contains 'Dropbox'

My best guess was:

find . -type l -iname '*Dropbox*'

But this returns nothing.

I want to find items such as:

com.adobe.illustrator.plist -> /Volumes/data/Dropbox (Personal)/Mackup/Library/Preferences/com.adobe.illustrator.plist
com.apple.Terminal.plist -> /Volumes/data/Dropbox (Personal)/Mackup/Library/Preferences/com.apple.Terminal.plist
com.noodlesoft.Hazel.plist -> /Volumes/data/Dropbox (Personal)/Mackup/Library/Preferences/com.noodlesoft.Hazel.plist

so that I can re-create the links without the (Personal) text. (If there's a way to do that with one line, that would be excellent!)

5

If your find supports -lname or -ilname (GNU extensions also supported by some BSDs (including macOS which your /Volumes suggest you might be using)).

find . -lname '*Dropbox*' -exec ls -ld {} +

Or case-insensitively:

find . -ilname '*dropbox*' -exec ls -ld {} +

If not (or even if yes if you want to do anything easily with those links or prefer a sorted list) and you have zsh (shipped by default on macOS), you could do:

zmodload zsh/stat
set -o extendedglob # for (#i) for case insensitive
link_match() {
  local target
  zstat -A target +link -- "${2-$REPLY}" &&
    [[ $target = $~1 ]]
}
ls -ld -- **/*(D@e:'link_match "(#i)*dropbox*"':)

Or to recreate the links:

zmodload zsh/stat
for l (**/*(D@))
  zstat -A target +link -- $l &&
    [[ $target = *"Dropbox (Personal)"* ]] &&
    rm -f -- $l &&
    ln -s -- ${target//" (Personal)"} $l

Note that any shell code can always be written on one line if need be, but I fail to see the point. Here, just join those lines together if you want it on one line.

To do something similar with bash and GNU or FreeBSD/macOS utilities, it's more complicated and would be less efficient:

LC_ALL=C find . -lname '*Dropbox (Personal)*' -exec bash -c '
  for l do
    target=$(readlink "$l" && echo .) || continue
    target=${target%??}
    rm -f "$l" &&
      ln -s -- "${target//" (Personal)"}" "$l"
  done' bash {} +
  • -lname works great, thanks! How would I write that script in bash? Or is zsh better for that sort of thing? (And sorry I shouldn't have said "one line"; I meant via script.) – Dan Nov 16 '17 at 12:35
  • 4
    @Ze'ev, zsh is better than bash for everything. – Stéphane Chazelas Nov 16 '17 at 12:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.