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)?

5
  • Excuse my ignorance, but what's "sequ"?
    – Kusalananda
    Jun 30, 2016 at 15:22
  • @Kusalananda It is just a word to be searched. Thank you for pointing it out! I made it clearer. Jun 30, 2016 at 15:22
  • So you have a bunch of symlinks called "Math*", and they point to LaTeX/TeX documents that you'd like to search for the string "sequ"? Or they point to directories with documents?
    – Kusalananda
    Jun 30, 2016 at 15:24
  • 1
    @Kusalananda Symlinks point to directories which have other directories. End things are .tex files. Jun 30, 2016 at 15:26
  • 1
    Don't have time for a proper answer right now, but something along the lines of basename $(readlink '{}') should be your friend.
    – user
    Jun 30, 2016 at 15:30

2 Answers 2

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.
6
  • Can you compare it to Michael's proposal about basename $(readlink) '{}')? Do you understand his point? Jun 30, 2016 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, 2016 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, 2016 at 15:42
  • 2
    Some formal people may certainly tells you that fgrep is deprecated. I will not.
    – Emmanuel
    Jun 30, 2016 at 15:59
  • 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, 2016 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
5
  • 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. Jul 1, 2016 at 4: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. Jul 1, 2016 at 4:18
  • I am considering how to trim long one-liners of the content here unix.stackexchange.com/q/293207/16920 Jul 1, 2016 at 4:37
  • 1
    @Masi Pipe the result to something like cut -c -80. Jul 1, 2016 at 4:46
  • Then you have a broken cut, that doesn't deal well with locales. shrug Jul 1, 2016 at 4:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .