如何检查 sed 是否更改了文件
- 2024-11-13 08:36:00
- admin 原创
- 21
问题描述:
我正在尝试找到一种聪明的方法来确定传递给 sed 的文件是否已被成功更改。
基本上,我想知道文件是否已被更改,而不必查看文件修改日期。
我之所以需要这个是因为如果 sed 成功替换了模式,我需要做一些额外的事情。
我目前有:
grep -q $pattern $filename
if [ $? -eq 0 ]
then
sed -i s:$pattern:$new_pattern: $filename
# DO SOME OTHER STUFF HERE
else
# DO SOME OTHER STUFF HERE
fi
上述代码有点昂贵,我希望能够在这里使用一些技巧。
解决方案 1:
虽然有点晚了,但为了其他人的利益,我发现“w”标志正是我想要的。
sed -i "s/$pattern/$new_pattern/w changelog.txt" "$filename"
if [ -s changelog.txt ]; then
# CHANGES MADE, DO SOME STUFF HERE
else
# NO CHANGES MADE, DO SOME OTHER STUFF HERE
fi
changelog.txt
将在自己的行上包含每个更改(即已更改的文本)。如果没有更改,changelog.txt
则为零字节。
一个非常有用的 sed 资源(也是我发现此信息的地方)是http://www.grymoire.com/Unix/Sed.html。
解决方案 2:
我相信你可能会发现这些 GNU sed 扩展很有用
t label
If a s/// has done a successful substitution since the last input line
was read and since the last t or T command, then branch to label; if
label is omitted, branch to end of script.
和
q [exit-code]
Immediately quit the sed script without processing any more input, except
that if auto-print is not disabled the current pattern space will be printed.
The exit code argument is a GNU extension.
这看起来正是您正在寻找的东西。
解决方案 3:
这可能对你有用(GNU sed):
sed -i.bak '/'"$old_pattern"'/{s//'"$new_pattern"'/;h};${x;/./{x;q1};x}' file || echo changed
解释:
/'"$old_pattern"'/{s//'"$new_pattern"'/;h}
如果模式空间(PS)包含old pattern
,则将其替换为new pattern
并将 PS 复制到保持空间(HS)。${x;/./{x;q1};x}
遇到最后一行时,交换到 HS 并测试是否存在任何字符串。如果在 HS 中发现字符串(即已进行替换),则交换回原始 PS 并使用退出代码退出,1
否则交换回原始 PS 并使用退出代码退出0
(默认)。
解决方案 4:
您可以将原始文件与 sed 输出进行比较,以查看它是否发生变化:
sed -i.bak s:$pattern:$new_pattern: "$filename"
if ! diff "$filename" "$filename.bak" &> /dev/null; then
echo "changed"
else
echo "not changed"
fi
rm "$filename.bak"
解决方案 5:
在 macOS 中我只需按如下方式操作:
changes=""
changes+=$(sed -i '' "s/$to_replace/$replacement/g w /dev/stdout" "$f")
if [ "$changes" != "" ]; then
echo "CHANGED!"
fi
我检查了一下,这比md5
和cksum
比较sha
快
解决方案 6:
你可以使用awk
:
awk '$0 ~ p { gsub(p, r); t=1} 1 END{ exit (!t) }' p="$pattern" r="$repl
“
我忽略了这个-i
功能:您可以根据需要使用 shell 进行重定向。
唉。下面有很多评论要求提供 shell 的基本教程。您可以按如下方式使用上述命令:
if awk '$0 ~ p { gsub(p, r); t=1} 1 END{ exit (!t) }' \n p="$pattern" r="$repl" "$filename" > "${filename}.new"; then
cat "${filename}.new" > "${filename}"
# DO SOME OTHER STUFF HERE
else
# DO SOME OTHER STUFF HERE
fi
我不清楚“在此处执行其他操作”在每种情况下是否相同。两个块中的任何类似代码都应进行相应的重构。
解决方案 7:
问题是s/foo/bar/;t;q8
它在第一行之后就退出了。要为多行或多替换情况设置适当的退出代码,您可以使用以下命令:
sed -i "s/foo/bar/w /dev/stdout" dir/file.txt | grep -q .
echo $?
它使用-i
来就地更改文件,w
将成功的替换发送到 的命令/dev/stdout
,然后我们用 读取它以查看输出是否为空。当未找到匹配项时以及当进行替换时,grep .
这将返回退出代码。例如,将其与 结合使用。1
`0`set -e
解决方案 8:
我知道这是一个老问题,使用 awk 代替 sed 也许是最佳选择,但如果要坚持使用 sed,一个想法是使用 -w 标志。w 标志的文件参数仅包含匹配的行。因此,我们只需检查它是否为空。
解决方案 9:
不要使用sed
来判断它是否更改了文件;相反,使用grep
来判断它是否要更改文件,然后使用来实际更改文件。请注意下面 Bash 函数末尾的一行用法sed
:sed
# Usage: `gs_replace_str "regex_search_pattern" "replacement_string" "file_path"`
gs_replace_str() {
REGEX_SEARCH="$1"
REPLACEMENT_STR="$2"
FILENAME="$3"
num_lines_matched=$(grep -c -E "$REGEX_SEARCH" "$FILENAME")
# Count number of matches, NOT lines (`grep -c` counts lines),
# in case there are multiple matches per line; see:
# https://superuser.com/questions/339522/counting-total-number-of-matches-with-grep-instead-of-just-how-many-lines-match/339523#339523
num_matches=$(grep -o -E "$REGEX_SEARCH" "$FILENAME" | wc -l)
# If num_matches > 0
if [ "$num_matches" -gt 0 ]; then
echo -e "
${num_matches} matches found on ${num_lines_matched} lines in file"\n "\"${FILENAME}\":"
# Now show these exact matches with their corresponding line 'n'umbers in the file
grep -n --color=always -E "$REGEX_SEARCH" "$FILENAME"
# Now actually DO the string replacing on the files 'i'n place using the `sed`
# 's'tream 'ed'itor!
sed -i "s|${REGEX_SEARCH}|${REPLACEMENT_STR}|g" "$FILENAME"
fi
}
例如,将其放在你的 ~/.bashrc 文件中。关闭并重新打开你的终端,然后使用它。
用法:
gs_replace_str "regex_search_pattern" "replacement_string" "file_path"
例如:替换do
为bo
,使“doing”变成“boing”(我知道,我们应该修正拼写错误而不是制造错误:)):
$ gs_replace_str "do" "bo" test_folder/test2.txt
9 matches found on 6 lines in file "test_folder/test2.txt":
1:hey how are you doing today
2:hey how are you doing today
3:hey how are you doing today
4:hey how are you doing today hey how are you doing today hey how are you doing today hey how are you doing today
5:hey how are you doing today
6:hey how are you doing today?
$SHLVL:3
输出截图:
参考:
解决方案 10:
perl -sple '$replaced++ if s/$from/$to/g;
END{if($replaced != 0){ print "[Info]: $replaced replacement done in $ARGV(from/to)($from/$to)"}
else {print "[Warning]: 0 replacement done in $ARGV(from/to)($from/$to)"}}' -- -from="FROM_STRING" -to="$DESIRED_STRING" </file/name>
示例:该命令将产生以下输出,说明每个文件所做的更改的数量。
perl -sple '$replaced++ if s/$from/$to/g;
END{if($replaced != 0){ print "[Info]: $replaced replacement done in $ARGV(from/to)($from/$to)"}
else {print "[Warning]: 0 replacement done in $ARGV(from/to)($from/$to)"}}' -- -from="timeout" -to="TIMEOUT" *
[Info]: 5 replacement done in main.yml(from/to)(timeout/TIMEOUT)
[Info]: 1 replacement done in task/main.yml(from/to)(timeout/TIMEOUT)
[Info]: 4 replacement done in defaults/main.yml(from/to)(timeout/TIMEOUT)
[Warning]: 0 replacement done in vars/main.yml(from/to)(timeout/TIMEOUT)
注意:我已从上述命令中删除-i
,因此它不会为正在尝试该命令的人更新文件。如果您想在文件中启用就地替换,请在上述命令-i
后添加。perl
解决方案 11:
检查 sed 是否更改了许多文件
递归替换一个目录中的所有文件
生成所有修改文件的列表
解决方法分为两个阶段:匹配 + 替换
g='hello.*world'
s='s/hello.*world/bye world/g;'
d='./' # directory of input files
o='modified-files.txt'
grep -r -l -Z -E "$g" "$d" | tee "$o" | xargs -0 sed -i "$s"
文件路径以$o
零分隔
解决方案 12:
$ echo hi > abc.txt
$ sed "s/hi/bye/g; t; q1;" -i abc.txt && (echo "Changed") || (echo "Failed")
Changed
$ sed "s/hi/bye/g; t; q1;" -i abc.txt && (echo "Changed") || (echo "Failed")
Failed
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件