我试图找到一种聪明的方法来确定传递给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
上面的代码有点贵,我希望能够在这里使用一些黑客。
答案 0 :(得分:21)
派对有点晚,但为了别人的利益,我找到了' 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。
答案 1 :(得分:9)
我相信您可能会发现这些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.
看起来你正在寻找什么。
答案 2 :(得分:6)
您可以改为使用awk
:
awk "/$pattern/"' { gsub( "'"$pattern"'", "'"$repl"'" ); t=1 }
1; END{ exit( !t )}'
我忽略了-i
功能:你可以根据需要使用shell做重定向。
答案 3 :(得分:6)
这可能适合你(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并退出,退出代码为{ {1}}(默认值)。答案 4 :(得分: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 :(得分:0)
我知道这是一个老问题,使用awk而不是sed也许是最好的主意,但如果想坚持使用sed,一个想法就是使用-w标志。 w标志的文件参数仅包含匹配的行。所以,我们只需要检查它是不是空的。
答案 6 :(得分:0)
不要使用sed
来判断它是否 已更改文件;相反,请使用grep
来确定它是否要更改文件,然后使用sed
来实际更改文件。请注意以下Bash函数的两端处的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 "\n${num_matches} matches found on ${num_lines_matched} lines in file"\
"\"${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
,以使“做”变成“无聊”(我知道,我们应该修复不创建它们的拼写错误:)):
$ 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
输出的屏幕截图:
答案 7 :(得分:0)
在macOS中,我只按以下步骤操作:
changes=""
changes+=$(sed -i '' "s/$to_replace/$replacement/g w /dev/stdout" "$f")
if [ "$changes" != "" ]; then
echo "CHANGED!"
fi
我检查了,这比md5
,cksum
和sha
的比较要快
答案 8 :(得分:0)
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
。