Trying to create a shell script to search a directory recursively and display a list of all php files that only contain 1 line
I think something is wrong with my IF statement but I'm not sure
#!/bin/bash
shopt -s nullglob
for f in *.php
do
if [ 'find . -type f | wc -l $f == 1' ];
then echo "$f"
fi
This will find "one-liners":
find . -type f -name '*.php' -exec grep -Hcm2 $ {} + | sed -n '/:1$/{s///;p}'
This one will find "one-liners" which happen to have more than one line, when all the lines except one are blank:
find . -type f -name '*.php' -exec grep -Hcm2 '[^[:space:]]' {} + |
sed -n '/:1$/{s///;p}'
The grep options -Hcm2 mean "Always print the filename, only print the count of the matches, and match at most two lines." The pattern $ matches any line, while the pattern "[^[:space:]]" matches any line containing a non-whitespace character. Ending the -exec with {} + tells find to provide a list of files rather than triggering the exec on every file, which is a lot more efficient. Finally, sed prints the lines which end with :1 (after removing the :1), which will be the filenames of the files for which the count of lines containing a non-whitespace character was exactly one.
This is arguably more efficient than wc because it normally stops reading at the second line, rather than reading entire files just to check if they have more than one line.
(Also, with respect to wc: if the file happens to have exactly one line, but that line is not terminated with a newline character, then wc will report that it has 0 lines. So if you're filtering wc output for equality to 1, you may miss a few files.)
If you have a reasonably recent bash, you can avoid find by enabling ** globs:
shopt -s globstar nullglob
grep -Hcm2 "[^[:space:]]" **/*.php | sed -n '/:1$/{s///;p}'
None of the above hacks work if you have files with newline characters in their filepaths. But you don't, right? :-)
awk to the rescue!
for f in *.php; do awk 'END{ if(NR==1) print FILENAME}' $f; done
for the recursive lookup you need to use find, one alternative can be
find -name *.php -print | xargs -L1 awk 'NR>1{exit} END{if(NR==1) print FILENAME}'
This will search for one-line PHP files recursively:
find -name '*.php' -exec bash -c '[[ "$(wc -l < "$0")" -eq 1 ]] && echo "$0"' '{}' ';'
If you want to test for the success or failure of a command in an if statement, you don't use the [ operator, but instead write it after the if directly:
if find . -type f | wc -l $f == 1; then
echo "$f"
fi
However, what I wrote above still doesn't make much sense and is not what I think you intended.
The [ itself is a command used to convert arithmetic and string comparison into an if-friendly form. You can combine it with output substitution (using the $(...) syntax) to test whether the output of a command is equal to 1.
if [ "$(wc -l < "$f")" -eq 1 ]; then
echo "$f"
fi