我想要什么:找到所有nginx访问日志文件,对其进行迭代(从中获取一些数据)。
我被困在for
循环中:
#!/bin/bash
logfiles="$(find /var/log/nginx -name 'access.log*')"
for lf in "$logfiles"
do
echo "file"
done
尽管有多个日志文件,但输出仅是一个“文件”字。怎么了?
答案 0 :(得分:4)
当你说
for lf in "$logfiles"
您的引号会保留find
输出中的空格。在这种情况下,引号是不正确的。删除它们将正确遍历文件:
$ for i in "`find . -iname '*.log'`"; do echo $i; done
./2.log ./3.log ./1.log
$ for i in `find . -iname '*.log'`; do echo $i; done
./2.log
./3.log
./1.log
但是有更好的方法:您应该流数据,而不是进行迭代。考虑这种模式:
$ find . -iname '*.log' | xargs -n 1 echo
./2.log
./3.log
./1.log
非常值得将您的头放在xargs
周围,这会将其标准输入转换为附加参数,以添加到自己的参数中,然后执行该参数。在这种简单情况下,我告诉xargs为文件的每1(echo
)分别运行命令-n 1
有几个原因xargs
是我尽可能使用的迭代运算符:首先,它非常聪明。使用for i in $(command)
遍历命令输出需要$(command)
以item1 item2 item3
的形式提供您的列表,如果任何项目包含特殊字符,则这些问题会引起问题,然后bash 将其解释为for参数的一部分。
以下是该空间的一个示例,该空间通常在bash中作为有效的输入字段spearator变得特别。
$ for i in `find . -iname '*.log'`; do echo $i; done
./4
tricky.log
./2.log
./3.log
./1.log
包含空格的文件4 tricky.log
现在引起了问题。
xargs
足够聪明,可以将它们分开。在某些情况下,可以通过更改$IFS
(输入字段分隔符)来解决此问题。但这变得很快。使用xargs
,您有更好的选择-具体来说,xargs
也可以使用空字符以-0
字符终止其输入流中的项目。其他程序find
也可以在输出中使用空字符来匹配xargs
的期望值。从这个意义上讲,xargs
和find
是很好的组合:
$ find . -iname '*.log' -print0 | xargs -0 -n 1 echo
./4 tricky.log
./2.log
./3.log
./1.log
但是,等等,还有更多!命令的下一步肯定是对grep
文件进行查找,以查找要查找的任何匹配行。如果行很大,那么您也将要并行化。 xargs
也可以这样做。您可以在管道中添加更多步骤进行过滤等。
最后,使用子shell替换$()
作为程序参数可能会导致意外命令,如果在使用它们时要非常小心,以避免在失败情况下产生意外参数。我曾经写过一个脚本,该脚本使用$()
查找mysql的源目录以进行一些首次安装。它说了类似remove -r /$(find / -iname mysqldir)
的内容。好吧,如果预期位置中没有mysqldir
变成rm -r /
。显然不是我想要的:天哪!
这就是为什么我尽可能使用并鼓励其他人使用xargs
的原因。
答案 1 :(得分:2)
删除此行中的引号:HAVING
但是看来您可能只有一个名为access.log的文件