这是我的代码:
#!/bin/bash -e
dirs=( * )
for f in "${dirs[@]}"
do
while IFS= read -r line; do
case "$line" in
*disabled\>true* )
sed -i '1i "$f"' list.txt;;
esac
done < "$f/config.xml"
done
我没有使用sed,而是尝试了echo和printf,但文件list.txt始终为空。为什么我无法追加档案?
echo "$f" >> list.txt;;
printf '%s\n' "$f" >> list.txt;;
测试文件夹下的示例config.xml文件:
<?xml version='1.0' encoding='UTF-8'?>
<project>
<disabled>true</disabled>
</project>
目标:打印&#34;测试&#34;如果test / config.xml中有<disabled>true
,则进入list.txt。
答案 0 :(得分:3)
在您的问题使用中有效地执行您尝试所做的事情(需要GNU实用程序):
grep -FZl 'disabled>true' */*.config.xml | xargs -0 dirname | tac > list.txt
这假设你想要:
仅记录在list.txt
中的目录名称(如果您需要(相对)文件路径,则只需删除| xargs -0 dirname
。< / p>
reverse 按字母顺序排列 - 如果您想升序,只需省略| tac
部分。
<强>解释强>
Glob */*.config.xml
有效地返回当前目录的任何子目录中config.xml
个文件的(相对)文件路径。
grep -FZl 'disabled>true'
在输入文件中搜索文字(-F
)disabled>true
,并且只有在找到第一个匹配时,才会停止搜索并打印输入文件路径(-l
),多个路径用NUL
个字符分隔。 (-Z
)。
xargs -0 dirname
传递输入,由NUL
(0
)拆分为dirname
的参数,从而产生目录名那些config.xml
个文件包含感兴趣的字符串的目录。
tac
撤消行
> list.txt
将整体结果写入文件list.txt
至于您尝试的问题:
dirs=( * )
捕获当前目录中任何类型的文件系统项(如果您知道当前目录只包含目录,则可能不会是一个问题);
dirs=( */ )
会仅限制与目录的匹配(但请注意,匹配将包含尾随/
)。
sed -i '1i ...' list.txt
中list.txt
指出的基本问题是user2021201中指出 至<{1}}如果它以空(零字节)文件开头:对于空输入文件,根本不会执行该脚本。
sed
解决方案;为了以递增方式将附加到文件中,>>
是正确的选择。此外,sed -i '1i "$f"' list.txt
,their answer在问题评论中指出,尝试在单引号内展开$f
字符串,这将无效 - 相反, literal "$f"
将被写入文件(假设文件是非空的)。
此外,通过使用1i
(在第1行之前插入),每个新条目将添加为第一个行,从而有效地生成包含匹配目录的list.txt
。在反向顺序。
一旦找到匹配项后不退出while
循环,您不仅会不必要地处理文件中的其余行,还会冒险添加手头的目录 multiple 如果在多行上找到搜索字符串,则次数为list.txt
。
正如Rany Albeg Wein中user2021201指出的那样,你的方法效率很低,因为(a)可以使用*/*.config.xml
这样的多级glob来代替循环,和(b)因为grep
可用于更有效地搜索每个文件的内容,并在找到第一个匹配后退出(使用grep -m1
或grep -q
或grep -l
,语义略有不同)。
答案 1 :(得分:2)
首先,请注意您的sed表达式不适用于空文件。我修改了代码,它满足了你的目标:
#!/bin/bash -e
for f in */config.xml # process all config.xml files
do
while IFS= read -r line; do
case "$line" in
*disabled\>true* )
# obtain directory name of the file
# and append it to list.txt
dirname "$f" >> list.txt
esac
done < "$f"
done
但是,我宁愿使用以下方法:
#!/bin/bash -e
for f in */config.xml
do
# -m1 - exit at first occurence for performance
if grep -m1 'disabled>true' "$f" >/dev/null; then
dirname "$f" >> list.txt
fi
done
甚至更简单:
grep -l 'disabled>true' */config.xml | cut -d/ -f1 > list.txt