bash脚本中的grep输出不同
我正在创建一个bash脚本,它将简单地使用grep在一堆日志中查找某个字符串 不过发生了一些有趣的事情 为了测试所有日志文件,文件名为test1.log、test2.log、test3.log等 使用grep命令时:bash脚本中的grep输出不同,bash,command-line-arguments,Bash,Command Line Arguments,我正在创建一个bash脚本,它将简单地使用grep在一堆日志中查找某个字符串 不过发生了一些有趣的事情 为了测试所有日志文件,文件名为test1.log、test2.log、test3.log等 使用grep命令时: grep -oHnR TEST Logs/test* 输出按预期包含文件夹中所有文件的所有实例 但是当使用下面的bash脚本中包含的命令时: #!/bin/bash #start grep -oHnR $1 $2 #end 输出仅显示1个文件中的实例 运行脚本时,我使用以下
grep -oHnR TEST Logs/test*
输出按预期包含文件夹中所有文件的所有实例
但是当使用下面的bash脚本中包含的命令时:
#!/bin/bash
#start
grep -oHnR $1 $2
#end
输出仅显示1个文件中的实例
运行脚本时,我使用以下命令:
bash test.bash TEST Logs/test*
下面是一个预期输出的示例(仅使用grep时发生的情况):
下面是使用bash脚本时收到的输出示例:
Logs/test2.log:8:TEST
Logs/test2.log:20:TEST
Logs/test2.log:41:TEST
有人能给我解释一下为什么会发生这种情况吗?要了解发生了什么,可以使用一个更简单的脚本:
#!/bin/bash
echo $1
echo $2
这将输出前两个参数,如您所要求的
您希望使用第一个参数,然后使用所有其他参数作为输入文件。所以像这样使用shift
:
#!/bin/bash
search=$1
shift
echo "$1"
echo "$@"
还要注意双引号的使用
在您的情况下,因为您希望搜索字符串和文件名以相同的顺序传递给grep
,所以您甚至不需要shift
:
#!/bin/bash
grep -oHnR -e "$@"
(我添加了
-e
,以防搜索字符串以-
开头)要了解发生了什么,可以使用更简单的脚本:
#!/bin/bash
echo $1
echo $2
这将输出前两个参数,如您所要求的
您希望使用第一个参数,然后使用所有其他参数作为输入文件。所以像这样使用shift
:
#!/bin/bash
search=$1
shift
echo "$1"
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
(如果您有四个日志文件)
命令行参数TEST
,Logs/test1.log
,Logs/test2.log
等将被命名为$1
,$2
,$3
等<代码>$1将是TEST
,$2
将是Logs/test1.log
当您仅使用$2
时,您只需忽略其余参数,只需使用一个日志文件
正确的版本如下:
#!/bin/bash
#start
grep -oHnR "$@"
#end
这将正确地传递所有参数,还可以处理文件名中的空格之类的污点(您的版本可能会遇到这些问题)。当您调用该行时
bash test.bash TEST Logs/test*
这将由shell转换为
bash test.bash TEST Logs/test1.log Logs/test2.log Logs/test3.log Logs/test4.log
(如果您有四个日志文件)
命令行参数TEST
,Logs/test1.log
,Logs/test2.log
等将被命名为$1
,$2
,$3
等<代码>$1将是TEST
,$2
将是Logs/test1.log
当您仅使用$2
时,您只需忽略其余参数,只需使用一个日志文件
正确的版本如下:
#!/bin/bash
#start
grep -oHnR "$@"
#end
这将正确地传递所有参数,并处理文件名中的空格等不干净的内容(您的版本可能会遇到这些问题)。调用脚本时,不带引号的
*
会受到影响
使用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
调用脚本时,未加引号的
*
会受到影响
使用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将把它扩展到Logs dir中名称以test
开头的每个文件
或者,更改脚本以允许命令行上有多个文件:
#!/bin/bash
hold=$1
shift
grep -oHnR $hold $@
您可能希望在bash调用时转义通配符:
bash test.bash TEST Logs/test\*
这样,它将以*
的形式传递给grep,否则shell将把它扩展到Logs dir中名称以test
开头的每个文件
或者,更改脚本以允许命令行上有多个文件:
#!/bin/bash
hold=$1
shift
grep -oHnR $hold $@
⁺用于提及
-e
:)⁺因为提到-e
:)哇!我对参数在bash中如何工作的想法是完全错误的。这很有道理。谢谢你的回复。哇!我对参数在bash中如何工作的想法是完全错误的。这很有道理。谢谢你的回复。