无法使用bash脚本附加到文件

时间:2016-03-10 21:04:40

标签: linux bash sh

这是我的代码:

#!/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。

2 个答案:

答案 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'在输入文件中搜索文字(-Fdisabled>true,并且只有在找到第一个匹配时,才会停止搜索并打印输入文件路径(-l),多个路径用NUL个字符分隔。 (-Z)。

  • xargs -0 dirname传递输入,由NUL0)拆分为dirname的参数,从而产生目录名那些config.xml个文件包含感兴趣的字符串的目录。

  • tac撤消行

  • > list.txt将整体结果写入文件list.txt

至于您尝试的问题

  • dirs=( * )捕获当前目录中任何类型的文件系统项(如果您知道当前目录只包含目录,则可能不会是一个问题); dirs=( */ )会仅限制与目录的匹配(但请注意,匹配将包含尾随/)。

  • sed -i '1i ...' list.txtlist.txt指出的基本问题是user2021201中指出 至<{1}}如果它以(零字节)文件开头:对于空输入文件,根本不会执行该脚本。

    • 此问题没有简单的单命令sed解决方案;为了以递增方式将附加到文件中,>>是正确的选择。
  • 此外,sed -i '1i "$f"' list.txttheir answer在问题评论中指出,尝试在单引号内展开$f 字符串,这将无效 - 相反, literal "$f"将被写入文件(假设文件是​​非空的)。
    此外,通过使用1i(在第1行之前插入),每个新条目将添加为第一个行,从而有效地生成包含匹配目录的list.txt。在反向顺序。

  • 一旦找到匹配项后不退出while循环,您不仅会不必要地处理文件中的其余行,还会冒险添加手头的目录 multiple 如果在多行上找到搜索字符串,则次数为list.txt

  • 正如Rany Albeg Weinuser2021201指出的那样,你的方法效率很低,因为(a)可以使用*/*.config.xml这样的多级glob来代替循环,和(b)因为grep可用于更有效地搜索每个文件的内容,并在找到第一个匹配后退出(使用grep -m1grep -qgrep -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