如何从一堆文件中仅选择shell脚本

4
我想找到所有我的bash脚本(我现在积累了很多)并自动通过 bash -n 运行它们。有什么快速的方法吗?我希望 grep 只匹配第一个非空行以 #!/bin/sh #!/usr/bin/env sh #!/usr/bin/env bash #!/bin/bash 开头的文件... 一种可行的答案当然是:
for file in *; do 
    if head -n 5 $file | grep "#!.*sh$" > /dev/null; then
        bash -n $file
    fi
done

但出于“正确性”的考虑,我该如何合理地在仅第一行的非空白(或替代的非空)字符上使用 grep?


1
file 命令比 grep 更能告诉你某个文件是不是 shell 脚本。我可以告诉你,bash -n 对一组脚本提供的有限检查非常弱,几乎毫无用处;大多数解释型语言很难(或者说根本不可能)通过静态分析提供太多帮助。 - msw
好的,我会接受任何可以得到的东西,如果它知道一个明显的语法错误,那对我很有帮助。我会查看 file,谢谢。 - Steven Lu
2
没有必要寻找“第一个非空行”。#!(“shebang”)必须是文件的第一行的第一个字符。因此,只需查看文件的第一行即可。 - rob mayoff
@robmayoff 啊,谢谢。我不知道那个。但是既然我想知道如何做到这一点,我必须知道。 - Steven Lu
1
@msw 你应该把 file 命令的建议作为答案发布。 - chepner
是的,实际上我选择了“file”解决方案。它更具语义化。 - Steven Lu
2个回答

3

使用find:

     find . -type f -exec grep -e "^#\!\/bin\/.*sh$" {} +

@jaypal,确定吗?我认为+会更有效率。+将尽可能多地将每个文件传递给grep。而\;则会为每个单独的文件调用grep - Sebastian
是的,+ 是高效的,因为 OP 提到他有很多文件,使用 + 将会批量传递文件名,而 {} \; 则会一次传递一个文件。我给你的答案点了赞! :) - jaypal singh

2

With GNU awk

awk '
FNR==1 && $0~/#!\/bin\/sh|#!\/usr\/bin\/env sh|#!\/usr\/bin\/env bash|#!\/bin\/bash/ { 
    print FILENAME " is shell script";
}
FNR>1 {
    nextfile
}' *
  • 您可以尝试调整上述的regex,将其缩减为#!
  • FNR==1regex一起使用,确保检查第一行是否为she-bang行。
  • nextfile将确保不会查看超出第一行的文件。
  • print仅用于记录日志。
  • FILENAME将打印正在检查的文件名。
  • *将匹配工作目录下的所有文件。

@StevenLu awk 唯一可怕的就是它的名字。 :) - jaypal singh
1
只有当第一行匹配时,才会调用“nextfile”。 - Stephane Chazelas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接