如何检查 sed 是否更改了文件

2024-11-13 08:36:00
admin
原创
46
摘要:问题描述:我正在尝试找到一种聪明的方法来确定传递给 sed 的文件是否已被成功更改。基本上,我想知道文件是否已被更改,而不必查看文件修改日期。我之所以需要这个是因为如果 sed 成功替换了模式,我需要做一些额外的事情。我目前有: grep -q $pattern $filename if [ $...

问题描述:

我正在尝试找到一种聪明的方法来确定传递给 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

我检查了一下,这比md5cksum比较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 函数末尾的一行用法sedsed

# 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"

例如:替换dobo,使“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 

输出截图:

在此处输入图片描述

参考:

  1. https://superuser.com/questions/339522/counting-total-number-of-matches-with-grep-instead-of-just-how-many-lines-match/339523#339523

  2. https://unix.stackexchange.com/questions/112023/how-can-i-replace-a-string-in-a-files/580328#580328

解决方案 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

https://askubuntu.com/questions/1036912/how-do-i-get-the-exit-status-when-using-the-sed-command/1036918#1036918

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   681  
  在项目管理领域,集成产品开发(IPD)流程以其高效、协同的特点,被众多企业视为提升产品竞争力的关键。IPD流程强调跨部门、跨职能的紧密合作,以确保产品从概念到市场各个环节的无缝衔接。然而,实现这一目标并非易事,它需要企业深刻理解并掌握IPD流程中的跨部门协作艺术。本文将深入探讨IPD流程中跨部门协作的三个关键点,旨在为...
IPD项目管理咨询   9  
  掌握IPD流程图:提升团队协作的关键路径在当今快速变化的商业环境中,团队协作的效率与效果直接关系到项目的成功与否。集成产品开发(Integrated Product Development,简称IPD)作为一种先进的研发管理理念,通过跨部门、跨领域的协同工作,能够显著提升产品开发的速度与质量。而IPD流程图,则是这一理...
IPD流程阶段   9  
  IPD流程概述:理解其核心价值与实施背景集成产品开发(Integrated Product Development,简称IPD)是一种先进的产品开发管理理念,它强调跨部门协作、市场导向和快速响应变化的能力。IPD流程不仅关注产品本身的技术创新,更注重将市场、研发、生产、销售等各个环节紧密集成,以实现产品从概念到市场的高...
华为IPD是什么   7  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程以其跨部门协作、高效决策和快速响应市场变化的特点,被众多企业视为提升竞争力的关键。然而,实践IPD流程并非易事,项目管理中的种种错误往往阻碍了其效果的充分发挥。本文旨在深入探讨如何在实施IPD流程时避免这些常见错误,...
IPD框架   7  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用