Shell脚本显示所有1行php文件

时间:2016-02-09 22:20:41

标签: linux bash sh

尝试创建一个shell脚本以递归方式搜索目录,并显示仅包含1行的所有php文件的列表

我认为我的IF声明有问题,但我不确定

#!/bin/bash
shopt -s nullglob
for f in *.php
do
if [ 'find . -type f | wc -l $f == 1' ];
then echo "$f"
fi

6 个答案:

答案 0 :(得分:2)

这将找到" one-liners":

find . -type f -name '*.php' -exec grep -Hcm2 $ {} + | sed -n '/:1$/{s///;p}'

这个会找到" one-liners"当除了一行之外的所有行都是空白时,碰巧有多行;

find . -type f -name '*.php' -exec grep -Hcm2 '[^[:space:]]' {} + |
   sed -n '/:1$/{s///;p}'

grep选项-Hcm2表示"始终打印文件名,只打印匹配的计数,并且最多匹配两行。"模式$匹配任何行,而模式"[^[:space:]]"匹配包含非空白字符的任何行。使用-exec结束{} +告诉find提供文件列表,而不是在每个文件上触发exec,这样效率会更高。最后,sed打印以:1结尾的行(在删除:1之后),这将是包含非空白字符的行数的文件的文件名。一个。

这可以说比wc更有效率,因为它通常会停止在第二行读取,而不是仅仅为了检查它们是否有多行来读取整个文件。

(另外,对于wc:如果文件恰好只有一行,但该行没有以换行符结尾,则wc将报告它有0行。因此,如果您将wc输出的等式过滤为1,则可能会遗漏几个文件。)

如果你有一个合理的最近bash,你可以通过启用find globs来避免**

shopt -s globstar nullglob
grep -Hcm2 "[^[:space:]]" **/*.php | sed -n '/:1$/{s///;p}'

如果您的文件路径中包含换行符的文件,则上述黑客都不起作用。但你不是吗,对吧? : - )

答案 1 :(得分:1)

awk救援!

 for f in *.php; do awk 'END{ if(NR==1) print FILENAME}' $f; done

对于需要使用find的递归查找,可以使用一种替代方法

 find -name *.php -print | xargs -L1 awk 'NR>1{exit} END{if(NR==1) print FILENAME}'

答案 2 :(得分:1)

这将以递归方式搜索单行PHP文件:

find -name '*.php' -exec bash -c '[[ "$(wc -l < "$0")" -eq 1 ]] && echo "$0"' '{}' ';'

如果要在if语句中测试命令的成功或失败,则不要使用[运算符,而是直接在if之后写入:

if find . -type f | wc -l $f == 1; then
  echo "$f"
fi

然而,我上面写的内容仍然没有多大意义,也不是我认为的意思。

[本身是一个用于将算术和字符串比较转换为if友好形式的命令。您可以将它与输出替换(使用$(...)语法)结合起来,以测试命令的输出是否等于1.

if [ "$(wc -l < "$f")" -eq 1 ]; then
    echo "$f"
fi

答案 3 :(得分:1)

Bash 4提供了&#34; globstar&#34; shell选项来处理递归需求:

shopt -s globstar
wc -l **/*.php | awk '$1==1' | sed 's/^ *[0-9]* *//'

或者如果你不喜欢sed,你可以把更多的东西放到管道的awk部分:

wc -l **/*.php | awk '$1==1{sub(/^ *[0-9]+ */,"");print}'

这两个解决方案,以及(此时)所发布的所有其他解决方案都会受到影响,因为长文件将被完整读取。你真的不需要这样做 - 你可以跳过任何文件,如果你看到第二行。所以,再次依靠Bash 4&#34; globstar&#34;递归:

awk 'FNR==1{a[FILENAME]} FNR==2{delete a[FILENAME];nextfile} END{for(f in a){print f}}' **/*.php

扩展以便于解释,这是:

awk '
  # Upon reading the first line of a file, add its name to an array.
  FNR==1 {a[FILENAME]}

  # Upon reading the second line, delete it from the array and move on.
  FNR==2 {delete a[FILENAME];nextfile}

  # Once we've processed all files, print what's left in the array.
  END {for(f in a){print f}}
' **/*.php

这应该从每个文件最多读取两行。可能比wc -lgrep -c快得多。

答案 4 :(得分:0)

使用包含globstarreadarray的Bash 4,纯粹的Bash解决方案非常简单:

shopt -s globstar nullglob dotglob # nocaseglob
for phpfile in **/*.php ; do
    readarray -n 2 lines < "$phpfile"
    [[ ${#lines[*]} == 1 ]] && printf '%q\n' "$phpfile"
done

处理带有任何合法字符(包括换行符)的文件名,以及以dot开头的文件名。它计算行未终止的单行文件(与使用wc的解决方案不同)。它从每个文件中最多读取两行,因此如果它遇到许多大文件,它不应该减慢很多。将%q格式与printf一起使用意味着可以安全地在shell命令中使用输出而无需额外引用,甚至名称中包含换行符的文件也会打印在一行中。取消注释nocaseglob以计算带有后缀的文件,例如.PHP.Php

答案 5 :(得分:-1)

for FILE in $(find . -type f -name *.php)
do
  if [ $(wc -l $FILE) -eq 1 ]
  then
    echo $FILE
  fi 
done

应该做的伎俩,尽管它有点笨拙。

更优雅的是

 find . -type f -name '*.php' -exec wc -l {} \; | egrep "^\s*1\s"