[英]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'
在输入文件中搜索文字( -F
) disabled>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
将输入(由NUL
( 0
)分割成参数)传递给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
:对于空输入文件,从不执行脚本。
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 -m1
或grep -q
或grep -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.