bash 脚本中的 grep 输出不同

grep output different in bash script

我正在创建一个 bash 脚本,它将简单地使用 grep 在一堆日志中查找特定字符串。

虽然发生了一些有趣的事情。

为了测试所有日志文件,文件被命名为 test1.log、test2.log、test3.log 等

使用grep命令时:

grep -oHnR TEST Logs/test*

输出包含预期的文件夹中所有文件的所有实例。

但是当使用命令但包含在下面的bash脚本中时:

#!/bin/bash
#start

grep -oHnR  

#end

输出仅显示来自 1 个文件的实例。

当运行脚本我使用的是以下命令:

bash test.bash TEST Logs/test*

这是预期输出的示例(仅使用 grep 时发生的情况):

Logs/test2.log:8:TEST    
Logs/test2.log:20:TEST    
Logs/test2.log:41:TEST    
Logs/test.log:2:TEST    
Logs/test.log:18:TEST

这里是使用 bash 脚本时收到的输出示例:

Logs/test2.log:8:TEST    
Logs/test2.log:20:TEST    
Logs/test2.log:41:TEST

有人可以向我解释为什么会这样吗?

要了解发生了什么,您可以使用更简单的脚本:

#!/bin/bash
echo 
echo 

这会输出 前两个 参数,正如您所要求的那样。

您想使用第一个参数,然后将其余所有参数用作输入文件。所以像这样使用 shift

#!/bin/bash
search=
shift

echo ""
echo "$@"

另请注意双引号的使用。

在你的情况下,因为你希望搜索字符串和文件名以相同的顺序传递给 grep,你甚至不需要 shift:

#!/bin/bash

grep -oHnR -e "$@"

(我添加了 -e 以防搜索字符串以 - 开头)

当您拨打线路时

bash test.bash TEST Logs/test*

这将由 shell 翻译成

bash test.bash TEST Logs/test1.log Logs/test2.log Logs/test3.log Logs/test4.log

(如果您有四个日志文件)。

命令行参数TESTLogs/test1.logLogs/test2.log等将被命名为</code>、<code></code>, ETC。; <code> 将是 TEST</code> 将是 <code>Logs/test1.log

仅使用</code>时,您只需忽略其余参数并仅使用一个日志文件即可。</p> <p>正确的版本应该是这样的:</p> <pre><code>#!/bin/bash #start grep -oHnR "$@" #end

这将正确传递所有参数,并处理文件名中的空格等问题(您的版本可能会遇到这些问题)。

当您调用脚本时,未加引号的 * 会受到 globbing 的影响。

使用 set -x 从脚本输出什么是 运行 使这一点更清楚。

$ ./greptest.sh TEST test*
++ grep -oHnR TEST test1.log
$ ./greptest.sh TEST "test*"
++ grep -oHnR TEST test1.log test2.log test3.log

在第一种情况下,bash 将 * 扩展到文件名列表中,而在第二种情况下,它被传递给 grep。在第一种情况下,您实际上有 >2 个参数(因为每个扩展的文件名都会成为一个参数)- 在脚本中添加 echo $# 也显示了这一点:

$ ./greptest.sh TEST test*
++ grep -oHnR TEST test1.log
++ echo 4
4
$ ./greptest.sh TEST "test*"
++ grep -oHnR TEST test1.log test2.log test3.log
++ echo 2
2

您可能想在 bash 调用中转义通配符:

bash test.bash TEST Logs/test\*

这样它将作为 * 传递给 grep,否则 shell 会将其扩展到日志目录中名称以 test 开头的每个文件.

或者,更改您的脚本以在命令行上允许多个文件:

#!/bin/bash
hold=
shift
grep -oHnR $hold $@