How do I grep this command that includes a wildcard?

How do I grep stderr?

The grep does not seem to do anything:

$ less /Users/raine/.nvm/versions/node/v5.5.0/lib/node_modules/* | grep "Not a file"
/Users/raine/.nvm/versions/node/v5.5.0/lib/node_modules/truffle is a directory
/Users/raine/.nvm/versions/node/v5.5.0/lib/node_modules/wunderline is a directory
/Users/raine/.nvm/versions/node/v5.5.0/lib/node_modules/yo is a directory

This is a very hacky use of less, and probably worthy of another question, but my intention is to find broken symlinks in this directory. It happens to be that less will print is a directory if it is valid and Not a file or directory if it is invalid. I believe it is worth asking anyway as this is indicative of my lack of understanding of wildcard operators stderr.

  • Clarified intention in OP. – Raine Revere Jun 29 '16 at 16:59
  • You have a valid point! I didn't ask the question directly. I would like to defend myself by saying that many quirky situations offer learning opportunities. In this case, I felt like it was an opportunity to learn more about the interaction between wildcards and grep. – Raine Revere Jun 29 '16 at 17:04
  • 3
    less ... 2>&1 | grep yo – Satō Katsura Jun 29 '16 at 17:04
  • 1
    Yes, you want to grep the error messages from less, and less prints error messages to stderr. – Satō Katsura Jun 29 '16 at 17:11
  • 1
    See here for a better way to find broken symlinks. – Satō Katsura Jun 29 '16 at 17:13

The wildcard has nothing to do with grep, all that grep sees is what is piped to it. The wildcard is expanded by the shell and the list of files it expands to is passed to less. So the issue has nothing at all to do with grep.

That said, if you're looking for broken links, you can do:

for f in /Users/raine/.nvm/versions/node/v5.5.0/lib/node_modules/*; do
     [ -e $(readlink -f "$f") ] || echo "$f"; 

That will iterate over all files and directories in /Users/raine/.nvm/versions/node/v5.5.0/lib/node_modules/, check if their target exists (readlink will print the file name iot was run on if that file isn't a link) and print the name if it doesn't.

A much better solution I just learned about is:

find /Users/raine/.nvm/versions/node/v5.5.0/lib/node_modules/ -xtype l 

The -xtype will test whether the target of the link is, in this case, a link, so it will only be true for dangling links.

| improve this answer | |
  • Thank you. I changed the OP to reflect the real question now that I understand it. Your answer is helpful, though I will go with 2>&1 as the accepted answer since it clears up my fundamental misunderstanding. – Raine Revere Jun 29 '16 at 17:19
  • 1
    @Raine in that case, please post the answer yourself and accept it so the question can be marked as answered. – terdon Jun 29 '16 at 17:21
  • find -L /Users/raine/.nvm/versions/node/v5.5.0/lib/node_modules/ -type l – Costas Jun 29 '16 at 17:29
  • @Costas find -xtype l is safer for reasons explained here. – terdon Jun 29 '16 at 17:31
  • I see now. Thanks. So for such security reason we have to add -path '/Users/raine/.nvm/versions/node/v5.5.0/lib/node_modules/*' – Costas Jun 29 '16 at 17:45

As @SatoKatsura pointed out in their comment, the (hacky) use of less is outputting to stderr, while grep reads from stdout. Though it is a poor solution to the actual task of finding dead symlinks, it can work by redirecting stderr to stdout:

less ~/.nvm/versions/node/v5.5.0/lib/node_modules/* 2>&1 | grep "Not a file"
| improve this answer | |

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