2

I want to expand the recursive search of symlinks to include only .tex files find . -type l -name "Math*" -exec grep -d "recurse" word {} +. Failed pseudocode 1

find . -type l -name "Math*" \
  -exec WHERE CHOOSE ONLY .tex files and Directories \
  -exec grep -d "recurse" word {} +

I cannot type a command for choosing .tex files and directories. In words, pseudocode 2

  1. Find all symlinks with name "Math" which point to directories.
  2. Recurse all symlinked directories (I think grep is limiting here possibly)
  3. Do basic grep word in file list

How can you do the step (2)?

2 Answers2

2

I think this must be one of the silliest command piplines I ever have concocted:

$ find . -type l -name "Math*" -print0 |
  xargs -0 -n 1 -IXXX find XXX/ -type f -name "*.tex" -print0 |
  xargs -0 fgrep "word"
  1. Find all symbolic links called Math*.
  2. Do find again on each found path, looking for *.tex files. The xargs need to use -n 1 to call find with no more than one pathname. The pathname will be put into the XXX placeholder.
  3. Call fgrep (i.e. grep -F since we have a fixed search string) with the string on found files.
Kusalananda
  • 333,661
  • Can you compare it to Michael's proposal about basename $(readlink) '{}')? Do you understand his point? – Léo Léopold Hertz 준영 Jun 30 '16 at 15:35
  • @Masi I'm wondering if that helps or not, actually. Well, possibly if you want to try to do it in a shorter pipeline, but my brain just started leaking after calling find from xargs so I can't think properly right now... – Kusalananda Jun 30 '16 at 15:40
  • 1
    @Masi, yes, -n 1, because I need to give exactly one path for to each of the find. I also need the / after XXX to be sure the Math symlink is followed. You can probably use a flag or other for that instead, but it was a cheap solution. – Kusalananda Jun 30 '16 at 15:42
  • 2
    Some formal people may certainly tells you that fgrep is deprecated. I will not. – Emmanuel Jun 30 '16 at 15:59
  • @Emmanuel Those formal people do not know that fgrep is not a standard utility, and therefore can't be deprecated ;-) – Kusalananda Jun 30 '16 at 16:11
  • 2
    @Masi - If you change the first -print0 for -exec readilnk -f {} \; it will then be similar to what Michael Kjörling suggests. But I do not believe it is needed since there is no real need to explicitly resolve the symlinks. – grochmal Jun 30 '16 at 17:21
1

One way to do it:

find . -type l -name 'Math*' -print0 | \
xargs -0 sh -c \
    'find -L "$@" -type f -name "*.tex" -exec fgrep word /dev/null {} +' sh

The sh -c '...' sh abomination is necessary to deal with the case when Math* can have spaces. Otherwise, when Math* doesn't expand to filenames with spaces, something like this would work:

find -L $(find . -type l -name 'Math*') -name '*.tex' \
    -exec fgrep word /dev/null {} +

The /dev/null makes sure fgrep prints a filename even when it only has a single file to search.

If you insist on the resolving links before grepping, it can be done too, at the price of making the assumptions that (1) your filenames don't contain newlines, and (2) you're using xargs from GNU findutils (BSD xargs doesn't accept -d):

find . -type l -name 'Math*' -exec readlink -f {} + | \
xargs -d '\n' sh -c \
    'find "$@" -type f -name "*.tex" -exec fgrep word /dev/null {} +' sh
Satō Katsura
  • 13,368
  • 2
  • 31
  • 50
  • Your second command. Your find . -type l -name 'Math* gives relative paths etc ./Mathematics. Your find -L $(find . -type l -name 'Math*') -name '*.tex' gives find: ‘./Mathematics’: No such file or directory. I think it is because the first command is giving a relative path. – Léo Léopold Hertz 준영 Jul 01 '16 at 04:07
  • 1
    @Masi Did you read the paragraph before that? It explains why the (simpler) second command doesn't work, and why you actually need the first one, or the last. You just re-discovered that out on your own. – Satō Katsura Jul 01 '16 at 04:18
  • I am considering how to trim long one-liners of the content here http://unix.stackexchange.com/q/293207/16920 – Léo Léopold Hertz 준영 Jul 01 '16 at 04:37
  • 1
    @Masi Pipe the result to something like cut -c -80. – Satō Katsura Jul 01 '16 at 04:46
  • Then you have a broken cut, that doesn't deal well with locales. shrug – Satō Katsura Jul 01 '16 at 04:58