查找文件夹中不包含空格的所有文件

时间:2015-08-04 15:46:00

标签: bash grep

我试图编写一个bash脚本来查找目录中不包含空格的所有文件,但我发现了一些困难。我使用find和grep的组合,它似乎适用于除空白之外的所有内容。我试过了两个:

namespace App\Controller;
use App\Controller\AppController;

class UsersController extends AppController {

    public function index() {
        // get all users from model
        $this->set('users', $this->User->get_all_users());
    }
}

find $d -name '*.js' | xargs grep -L '[ \t]*'

两者都不起作用。如何才能正确匹配空格?

编辑:澄清一下,我想搜索文件内部,而不是文件名。

2 个答案:

答案 0 :(得分:2)

find . -type f \( -exec grep -q '[[:space:]]' {} \; -o -print \)

当grep找到带有空格的文件时,它会返回&#34; success&#34;。如果-exec中的命令成功,find允许下一个谓词运行;但是,如果下一个运算符为&{34; OR&#34; -o,则find仅允许下一个谓词在-exec中的命令不< / em>成功。这就是上述工作的原因:它匹配具有空格的文件,但只打印出名称​​不匹配的文件。 (括号是必要的,因此-type f也不会受到&#34;或&#34; - 否则我们会得到所有不是文件的东西,与目录名称一样。)如果您愿意,可以将其限制为* .js文件:

find . -type f -name '*.js' \
    \( -exec grep -q '[[:space:]]' {} \; -o -print \)

值得注意的是,grep如果您想要检测换行符,则不是一个好工具。为此,你可能会考虑一些暴力:

for file in "$d"/*.js; do
    origcheck=$(md5sum < "$file")
    nospacecheck=$(tr -d '[:space:]' < "$file" | md5sum)
    [[ "$origcheck" = "$nospacecheck" ]] || printf '%s\n' "$file"
done

这将创建每个匹配文件的校验和,并且没有所有空格。如果校验和相同,则文件永远不会有任何空格。 (但许多文件以换行符结尾,所以要小心。)

关于原始方法的说明:

我计算机上的grep联机帮助页

-L … Only the names of files not containing selected lines are written…
     If the standard input is searched, the string ``(standard input)'' is written.

但是the standards没有提到-L,因此无法保证它在其他实现中的行为方式如此。以下是一些实验:

快速健全检查:

$ grep -L '[a]' <<< 'a'
$ grep -L '[a]' <<< 'b'
(standard input)

到目前为止,非常好。

$ grep -L '[ \t]' <<< 'ab c'
$ grep -L '[ \t]' <<< $'ab\tc'
(standard input)

(在bash中,我们可以使用特殊形式的引用来编写像制表符和换行符这样的文字字符来解释反斜杠转义。这里,$'\t'扩展为文字制表符。)所以我们看到带有字符串的字符串space是匹配项,但带有文字选项卡的字符串不匹配。

$ grep -L '[ \t]' <<< t
$ grep -L '[ \t]' <<< '\'
$

事实上,字面意思是&#39;匹配是反斜杠-t不是 tab 到grep的证据。字面反斜杠也是一个匹配,所以似乎表达式由grep在面值处采用。好吧,我们知道一种表达真实标签的方法:

$ grep -L $'[ \t]' <<< $'\t'
$ grep -L $'[ \t]' <<< 't'
(standard input)
$ grep -L $'[ \t]' <<< '\'
(standard input)

所以原始表达式的问题在于我们没有找到没有空格或标签的文件:我们正在寻找没有空格,反斜杠或者没有空格的文件。字符。

到目前为止,我避免谈论*,但是匹配零个或多个字符,所以即使你让字符类匹配正确的字符,用星号跟随它也不会得到你想要的结果:

$ grep -L $'[ \t]*' <<< $'\t'
$ grep -L $'[ \t]*' <<< t
$

上述输入字符串是否包含零个或多个制表符?是。他们俩都这样做。你只想找到一个角色,所以不要让它变得复杂。

但是[[:space:]]呢?

$ grep -L '[[:space:]]' <<< ' '
$ grep -L '[[:space:]]' <<< $'\t'
$ grep -L '[[:space:]]' <<< x
(standard input)

嗯,这个我无法解释。它在我测试它的两台机器上都可以正常工作(OS X和Linux)。也许你最初在&#39; [[:space:]]&#39;之后有一个星号?我不知道。这是一个谜。

find … | xargs

将管道find添加到xargs可能会引入问题。 shell对参数名称进行单词分析,这样的管道可能会丢失有关传递的实际文件名中的空格的信息。这是一个非常罕见的案例,许多人根本不会思考或关心它,但它可以而且确实发生了,而且解决它并不是很难。

首先,find-exec,因此不是

find . -some -predicate | xargs some command

你可以简单地写

find . -some -predicate -exec some command {} +

如果出于某种原因,你真的想要使用xargs(也许你想利用并行化),那么告诉find和xargs文件名是用NUL字符而不是空格分隔的:

find . -some -predicate -print0 | xargs -0 some command

答案 1 :(得分:0)

您可以使用grep简单地排除结果(-v, --invert-match select non-matching lines,而不是),其中包含find结果中的空格......例如:

查找没有空格的文件名的解决方案

find $d -name '*.js' | grep -v " "

似乎很棒!

根据您的修改,以下解决方案应该适合您,结果只是不包含空白内容的文件:

查找内容不包含空格的文件的解决方案(文件名在此解决方案中可以包含空格。)

find $d -name '*.js' |grep -iRlv " "

我认为两者的组合可以起作用,如果您只想返回除了那些文件内容没有空格之外不包含空格的文件名:

find $d -name '*.js' |grep -iRlv " " | grep -v " "