简体   繁体   English

grep输出在bash脚本中有所不同

[英]grep output different in bash script

I am creating a bash script that will simply use grep to look through a bunch of logs for a certain string. 我正在创建一个bash脚本,该脚本将仅使用grep来查看一堆日志中的某个字符串。

Something interesting happens though. 有趣的事情发生了。

For the purpose of testing all of the log files the files are named test1.log, test2.log, test3.log, etc. 为了测试所有日志文件,文件被命名为test1.log,test2.log,test3.log等。

When using the grep command: 使用grep命令时:

grep -oHnR TEST Logs/test*

The output contains all instances from all files in the folder as expected. 输出包含预期的文件夹中所有文件的所有实例。

But when using a command but contained in the bash script below: 但是当使用命令但包含在下面的bash脚本中时:

#!/bin/bash
#start

grep -oHnR $1 $2

#end

The output displays the instances from only 1 file. 输出仅显示1个文件中的实例。

When running the script I am using the following command: 运行脚本时,我使用以下命令:

bash test.bash TEST Logs/test*

Here is an example of the expected output (what occurs when simply using grep): 这是预期输出的示例(仅使用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

and here is an example of the output received when using the bash script: 这是使用bash脚本时收到的输出示例:

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

Can someone explain to me why this happens? 有人可以向我解释为什么会这样吗?

When you call the line 拨打电话时

bash test.bash TEST Logs/test*

this will be translated by the shell to 这将由外壳程序翻译为

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

(if you have four log files). (如果您有四个日志文件)。

The command line parameters TEST , Logs/test1.log , Logs/test2.log , etc. will be given the names $1 , $2 , $3 , etc.; 命令行参数TESTLogs/test1.logLogs/test2.log等将被赋予名称$1$2$3等。 $1 will be TEST , $2 will be Logs/test1.log . $1将是TEST$2将是Logs/test1.log

You just ignore the remaining parameters and use just one log file when you use $2 only. 仅使用$2时,您只需忽略其余参数,仅使用一个日志文件。

A correct version would be this: 正确的版本是这样的:

#!/bin/bash
#start

grep -oHnR "$@"

#end

This will pass all the parameters properly and also take care of nastinesses like spaces in file names (your version would have had trouble with these). 这样可以正确地传递所有参数,还可以处理文件名中的空格之类的麻烦事情(您的版本可能会遇到麻烦)。

To understand what's happening, you can use a simpler script: 要了解发生了什么,可以使用一个更简单的脚本:

#!/bin/bash
echo $1
echo $2

That outputs the first two arguments, as you asked for. 根据您的要求,输出前两个参数。

You want to use the first argument, and then use all the rest as input files. 您要使用第一个参数,然后将其余所有参数用作输入文件。 So use shift like this: 因此,使用shift这样:

#!/bin/bash
search=$1
shift

echo "$1"
echo "$@"

Notice also the use of double quotes. 还请注意使用双引号。

In your case, because you want the search string and the filenames to be passed to grep in the same order, you don't even need to shift : 在您的情况下,因为您希望将搜索字符串和文件名以相同的顺序传递到grep ,所以您甚至不需要shift

#!/bin/bash

grep -oHnR -e "$@"

(I added the -e in case the search string begins with - ) (我添加了-e以防搜索字符串以-开头)

The unquoted * is being affected by globbing when you are calling the script. 未加引号*受着通配符 ,当你调用脚本。

Using set -x to output what is running from the script makes this more clear. 使用set -x输出脚本中正在运行的内容可以使这一点更加清楚。

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

In the first case, bash is expanding the * into the list of file names versus the second case it is being passed to grep. 在第一种情况下,bash将*扩展到文件名列表,而第二种情况是将bash传递给grep。 In the first case you actually have >2 args (as each filename expanded would become an arg) - adding echo $# to the script shows this too: 在第一种情况下,您实际上有> 2个args(因为扩展的每个文件名都将成为arg)-在脚本中添加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

You probably want to escape the wildcard on your bash invocation: 您可能想在bash调用中转义通配符:

bash test.bash TEST Logs/test\*

That way it'll get passed through to grep as an * , otherwise the shell will have expanded it to every file in the Logs dir whose name starts with test . 这样,它将以*传递给grep,否则shell会将其扩展到Logs目录中名称以test开头的每个文件。

Alternatively, change your script to allow more than one file on the command line: 或者,更改脚本以在命令行上允许多个文件:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM