尝试遍历目录中的所有文件,检查它们是否存在字符串,如果它不存在则添加它。这就是我所拥有的:
#!/bin/bash
FILES=*
for f in $FILES
do
echo "Processing $f file..."
if grep -Fxq '<?xml version="1.0" encoding="UTF-8"?>' $f
then
continue
else
echo '<?xml version="1.0" encoding="UTF-8"?>' | cat - $f > temp && mv temp $f
fi
done
...但是脚本在第一个循环后停止。有什么想法吗?
答案 0 :(得分:2)
更简单的解决方案是使用-i
工具的就地编辑选项sed
,如下所示
sed -i '1{/^<?xml version="1.0" encoding="UTF-8"?>/!{
s/^/<?xml version="1.0" encoding="UTF-8"?>\n/}}' /path/to/files/*
我们上面做了什么
-i
的inplace选项sed
对写入文件的文件进行任何更改。1{}
我们只处理文件的第一行/^<?xml version="1.0" encoding="UTF-8"?>/!
部分检查字符串不(注意最后的!)是否存在于行的开头。如果上述条件不成立,我们使用
替换^
行的开头(<?xml version="1.0" encoding="UTF-8"?>\n
)
s/^/<?xml version="1.0" encoding="UTF-8"?>\n/
也就是说,在原始脚本中,我看到了像FILES
这样的变量。不鼓励使用大写变量作为用户变量,因为它们被保留为环境变量并可能导致冲突。所以请改用files
。
再次做
file=*
具有[ word splitting ]的含义,如果您的非标准文件包含空格甚至是新行,则会产生不需要的结果。你能做的是
files=( * ) # This put the files in an array
for file in "${files[@]}" # Double quoting the array prevents word splitting
do
# Do something with "$file" but why bother when you've a one-liner with sed? ;-)
done
注意:对于sed
手动访问[ here ]
答案 1 :(得分:1)
我想澄清一下我在评论中看到的关于单词拆分和文件名扩展的一些内容。
使用变量赋值时,引用Bash Reference Manual,只进行以下扩展:代码扩展,参数扩展,命令替换,算术扩展。这意味着变量$files
中只有一个星号,因为没有发生文件名扩展。因此,此时您不必担心换行符,空格等,因为变量中没有实际文件。您可以使用declare -p files
来查看此内容。
这是您在分配变量时不必引用的原因。
var=$othervariable
与:
相同var="$othervariable"
现在,当您在for循环$files
中使用变量for f in $files
时(请注意,由于文件扩展不会发生,因此您无法引用$files
)该变量会被扩展并且经历分词。但实际值是 JUST 星号和分词不会对结果做任何事情!再次引用manual:
分词后,除非设置了-f选项(参见Set 内置),Bash扫描每个单词的字符'*','?'和'['。 如果出现其中一个字符,则该单词被视为a 模式,并替换为按字母顺序排序的文件名列表 匹配模式(参见模式匹配)。
这意味着文件名扩展在变量扩展和单词拆分后完成。因此,文件名扩展扩展的文件不会被IFS拆分!因此,以下代码可以正常工作:
#!/usr/bin/env bash
files=*
for f in $files; do
echo "<<${f}>>"
done
并正确输出:
<<file with many spaces>>
<<filewith* weird characters[abc]>>
<<normalfile>>
较短版本显然是使用for f in *
而不是变量$files
。您也肯定想引用循环中$f
的任何用法,因为该扩展确实经历了单词拆分。
这就是说,你的循环应该正常运行。