简体   繁体   English

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

[英]not able to append to a file using bash script

This is my code: 这是我的代码:

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

Instead of sed, I tried echo and printf too but the the file list.txt is always empty. 我没有使用sed,而是尝试了echo和printf,但文件list.txt始终是空的。 Why am I not able to append to file? 为什么我无法追加档案?

echo "$f" >> list.txt;;
printf '%s\n' "$f" >> list.txt;;

sample config.xml file under test folder: 测试文件夹下的示例config.xml文件:

<?xml version='1.0' encoding='UTF-8'?>
<project>
<disabled>true</disabled>
</project>

Goal: Print "test" into list.txt, if test/config.xml has <disabled>true in it. 目标:如果test / config.xml中的<disabled>true ,则将“test”打印到list.txt中。

To efficiently do what you attempted to do in your question use (requires GNU utilities): 要有效地执行您在问题中尝试做的事情(需要GNU实用程序):

grep -FZl 'disabled>true' */*.config.xml | xargs -0 dirname | tac > list.txt

This assumes that you want: 这假定你想要:

  • only directory names recorded in list.txt (simply remove | xargs -0 dirname if you want the (relative) file paths). 只有list.txt记录的目录名称(如果你想要(相对) 文件路径,只需删除| xargs -0 dirname )。

  • in reverse alphabetical order - if you want ascending order, simply omit the | tac 反向字母顺序 - 如果你想升序,只需省略| tac | tac part. | tac部分。

Explanation: 说明:

  • Glob */*.config.xml efficiently returns the (relative) file paths of config.xml files in any subdirectories of the current dir. Glob */*.config.xml有效地返回当前目录的任何子目录中config.xml文件的(相对)文件路径。

  • grep -FZl 'disabled>true' searches for literal ( -F ) disabled>true in the input files and, only if and once the first match is found, stops searching and prints the input file path ( -l ), with multiple paths separated with NUL chars. grep -FZl 'disabled>true'在输入文件中搜索文字( -Fdisabled>true ,并且只有在找到第一个匹配项时,才会停止搜索并打印输入文件路径( -l ),具有多个路径用NUL字符分隔。 ( -Z ). -Z )。

  • xargs -0 dirname passes the input, split into arguments by NUL ( 0 ), to dirname , which results in the directory names of those directories whose config.xml files contained the string of interest. xargs -0 dirname将输入(由NUL0 )分割成参数)传递给dirname ,这导致config.xml文件包含感兴趣字符串的那些目录的目录名

  • tac reverses the lines tac逆转了线条

  • > list.txt writes the overall result to file list.txt > list.txt将整个结果写入文件list.txt


As for the problems with your attempt : 至于你的尝试问题

  • dirs=( * ) captures any type of filesystem item in the current dir (if you know that the current dir only contains directories , that may not be a problem); dirs=( * )捕获当前目录中的任何类型的文件系统项(如果您知道当前目录只包含目录 ,那可能不是问题);
    dirs=( */ ) would restrict matching to directories only (but note that the matches would include the trailing / ). dirs=( */ )将仅限制与目录的匹配(但请注意匹配将包括尾随/ )。

  • The fundamental problem with sed -i '1i ...' list.txt , as user2021201 points out in their answer , is that nothing is ever added to list.txt if it starts out as an empty (zero-byte) file: the script is simply never executed for an empty input file. sed -i '1i ...' list.txt的基本问题,正如user2021201他们的回答中指出的那样,如果它以 (零字节)文件开头,则没有任何东西被添加list.txt :对于空输入文件,从不执行脚本。

    • There is no simple, single-command sed solution for this problem; 对于这个问题,没有简单的单命令sed解决方案; for appending to a file incrementally, >> is the right choice. 为了逐步附加到文件, >>是正确的选择。
  • Additionally, sed -i '1i "$f"' list.txt , as Rany Albeg Wein points out in a comment on the question, tries to expand $f in inside a single-quoted string, which won't work - instead, literal "$f" will be written to the file (assuming the file is nonempty). 另外, sed -i '1i "$f"' list.txt ,正如Rany Albeg Wein在对该问题的评论中指出的那样,尝试在单引号字符串中扩展$f ,这将无效 - 相反, 文字 "$f"将写入文件(假设文件非空)。
    Also, by using 1i (insert before the 1st line), each new entry will be added as the first line, effectively resulting in list.txt containing the matching dirs. 此外,通过使用1i (在第1行之前插入),每个新条目将被添加为第一行,从而有效地产生包含匹配目录的list.txt in reverse order. 相反的顺序。

  • By not exiting the while loop once a match is found, you not only needlessly process the remaining lines in the file, but you also risk adding the directory at hand multiple times to list.txt in the event that the search string is found on more than 1 line. 如果不退出while循环一旦找到匹配,你不仅无谓地处理文件中剩余的线路,但也风险手头多次添加目录list.txt在事件中搜索字符串更多的发现超过1行。

  • As user2021201 points out in their answer , your approach is inefficient, because (a) a multi-level glob such as */*.config.xml can be used in lieu of a loop, and (b) because grep can be used to more efficiently search the contents of each file and exit once the first match is found (with grep -m1 or grep -q or grep -l , all with slightly different semantics). 正如user2021201他们的回答中指出的那样,你的方法是低效的,因为(a)可以使用多级glob,例如*/*.config.xml来代替循环,以及(b)因为grep可以用来更有效地搜索每个文件的内容并在找到第一个匹配后退出(使用grep -m1grep -qgrep -l ,所有语义略有不同)。

First, note that your sed expresion is not working with empty files. 首先,请注意您的sed表达式不适用于空文件。 I modified the code and it satisfies your goal: 我修改了代码,它满足了你的目标:

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

However, I'd rather use the following approach: 但是,我宁愿使用以下方法:

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

Or even simpler: 甚至更简单:

grep -l 'disabled>true' */config.xml | cut -d/ -f1 > list.txt

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM