0

We want to grep the corresponding files that including some fixed strings, and then output those files just only in ls -l format.
For example:
A) the following method with multiple -exec output both the grep and ls -l.

# 
# 
# find /usr/bin -type f -exec grep -Eil '#\!\/usr\/bin\/csh' {} \; -exec ls -l  {} \; >scripts_csh_list 2>&1
# 
# 
# 
# cat scripts_csh_list      
/usr/bin/which
-r-xr-xr-x    1 bin      bin            1191 Sep 06 2007  /usr/bin/which
#  
#  

B) But we want to the better method output only with ls -l ... , and then we failed via sh -c 'grep ... {}'
Notes: all the following different combined commands for the find -exec ... output the same failed result.

#                                                                                                                
# 
# find /usr/bin -type f -exec sh -c 'grep -Eil '\/usr\/bin\/csh' {} && ls -ltr  {}' \; >scripts_csh_list 2>&1t
#  
# 
# tail -6 scripts_csh_list
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
# 
# 
# 
# find /usr/bin -type f -exec sh -c ' grep -Eil '\/usr\/bin\/csh' {} '  \; >scripts_csh_list 2>&1  
# 
# 
# tail -6 scripts_csh_list                                                                         
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
# 
# 
# find /usr/bin -type f -exec sh -c ' grep -Eil '\/usr\/bin\/csh' "{}" '  \; >scripts_csh_list 2>&1  
# 
# 
# tail -6 scripts_csh_list                                                                         
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
# 
# 
# 
# find /usr/bin -type f -exec sh -c " grep -Eil '\/usr\/bin\/csh' {} "  \; >scripts_csh_list 2>&1  
# 
# 
# tail -6 scripts_csh_list                                                                         
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
# 
# 
# 
# find /usr/bin -type f -exec sh -c " grep -Eil '\/usr\/bin\/csh' {} "  \; >scripts_csh_list 2>&1  
# 
# 
# tail -6 scripts_csh_list                                                                         
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
grep: 0652-033 Cannot open {}.
# 
# 
lylklb
  • 193
  • 4
  • 13
  • 1
    If you don't want `grep` to output anything, why are you using `-l`? Why not use `-q`? – muru Jun 15 '23 at 13:04
  • so, hold on, what's the goal there? If `-exec grep ... \;` works, why change it to `-exec sh -c 'grep ...' \;`? Especially when `exec grep \; -exec ls \;` pretty much does the same thing as `-exec sh -c 'grep && ls' \;`, i.e. run `ls` only if grep succeeds – ilkkachu Jun 15 '23 at 13:08
  • now, the error there looks odd, but it seems to me that your `find` is one of those that doesn't expand `{}` embedded in other strings. Which is a good thing, as it's a very error-prone way to do anything. Pass the filename as an argument to the `-exec sh -c ... ` script – ilkkachu Jun 15 '23 at 13:09
  • you may want to see e.g. [How does this find command using "find ... -exec sh -c '...' sh {} +" work?](https://unix.stackexchange.com/q/93324/170373) – ilkkachu Jun 15 '23 at 13:11
  • Yes, the embedded {} did not take effect .... within sh -c – lylklb Jun 15 '23 at 13:12

2 Answers2

3

There is a lot of what appears to be unnecessary quoting and escaping in the original. While I don't have any csh scripts in /usr/bin, I was able to find bash scripts and get the ls output you appear to want with the following:

find /usr/bin -type f -exec grep -q '#!/usr/bin/bash' {} \; -exec ls -l {} \; 2> /dev/null

(I verified this by running without the second -exec, e.g.,

find /usr/bin -type f -exec grep -q '#!/usr/bin/bash' {} \; 2> /dev/null

and inspecting the results.)

For a slightly different output listing, you could also do

find /usr/bin -type f -exec grep -q '#!/usr/bin/bash' {} \; -ls 2> /dev/null

where find stats each matching file itself, directly, and returns ls-like results.

I piped errors to /dev/null simply to make things more readable as I was testing; for similar reasons, I didn't pipe the output to a file.

Note that I am using bash as my shell, so wrapping the grep expression in single quotes ('...') was sufficient to prevent any interpretation of its contents (not that there is much to worry about, forward slashes (/) aren't special for the shell, at least not for bash. If you are using a shell with different quoting rules, YMMV.

As to the command, unless you use the -o option, find will AND together all criteria, so this runs ls -l ONLY on regular files (the type f you included) that pass the grep check. As noted in the comments on your question, grep -q likely does what you want, which is simply determine if the file in question ({}) matches or not.

EDIT: As noted in the comments, if the user's shell is csh, they will need to escape the ! in the grep expression: '#\!/usr/bin/bash' should work.

  • The OP is likely using csh where quoting works differently. See [How to use a special character as a normal one in Unix shells?](https://unix.stackexchange.com/a/296147) – Stéphane Chazelas Jun 15 '23 at 13:47
  • Using `-exec ls -ld {} +` with `+` (and -d for good measure) would avoid running one `ls` per file. With a `grep` with support for `-Z`/`--null` and a `xargs` that supports `-r0`, that could also be done for `grep`, but it doesn't look like the OP's system is a GNU one. – Stéphane Chazelas Jun 15 '23 at 13:55
  • @StéphaneChazelas from the reference you posted it looks like `'#\!/usr/bin/bash'` would suffice. – Peter Whittaker Jun 15 '23 at 13:57
  • Yes, or `\#\!/usr/bin/bash` without the quotes to make it work in both sh-like and csh-like shells. – Stéphane Chazelas Jun 15 '23 at 15:43
0

Finally we did the following correct method via sh -c 'grep ... ' with find -exec commands. Thanks all!

# find /usr/bin -type f -exec sh -c ' grep -q ''\#'\!/usr/bin/csh'  "$1" && ls -l "$1" ' sh {} \; >scripts_csh_list 2>&1

# head -3  scripts_csh_list                                                                                             
-r-xr-xr-x    1 bin      bin            1191 Sep 06 2007  /usr/bin/which
AdminBee
  • 21,637
  • 21
  • 47
  • 71
lylklb
  • 193
  • 4
  • 13