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
(如果您有四个日志文件)。
命令行参数TEST
、Logs/test1.log
、Logs/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 $@
我正在创建一个 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
(如果您有四个日志文件)。
命令行参数TEST
、Logs/test1.log
、Logs/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 $@