Dan*_*len 3 bash sed find regular-expression replace
这是我未能掌握的一般主题的具体示例。
多年来,我一直使用 regex 和 sed 递归地查找/替换目录中所有文件中出现的所有字符串,使用如下所示:
#FIND $GLOBALS['timechecks'] and REPLACE with completely_different_string
shopt -s globstar dotglob;
for file in /var/www/**/*; do
if [[ -f $file ]] && [[ -w $file ]]; then
sed -i -- 's/\$GLOBALS\['\''timechecks'\''\]/completely_different_string/g' "$file"
fi
done
Run Code Online (Sandbox Code Playgroud)
问题是,在我不知道的情况下,在 bash 中使用 Regex 有一些基本的东西。结果,我无法找出特定示例的解决方案。
目标字符串我被卡住的地方
$GLOBALS['timechecks']=addTimeCheck_sparky($GLOBALS['timechecks'], number_format(microtime(true),6,'.',''), __LINE__, basename(__FILE__));
Run Code Online (Sandbox Code Playgroud)
正则表达式我想出了不工作
这只是我的脚本中的 sed 行以及我想出的搜索正则表达式,但无济于事。
\$GLOBALS\['\''timechecks'\''\]=addTimeCheck_sparky[(]$GLOBALS\['\''timechecks'\''\][,][ ]number_format[(]microtime[(]true[)][,]6[,]'\''\.'\''[,]'\'''\''[)][,][ ]__LINE__[],[ ]basename[(]__FILE__[)][)][;]
Run Code Online (Sandbox Code Playgroud)
正则表达式调试器
我在这个例子中使用了一个正则表达式调试器,它显示了正则表达式找到我的目标字符串,但它对我不起作用。调试器位于此链接。这是它显示的查找我的目标字符串的正则表达式:
\$GLOBALS\['timechecks\'\]=addTimeCheck_sparky\(\$GLOBALS\[\'timechecks\'\], number_format\(microtime\(true\),6,\'\.\',''\), __LINE__, basename\(__FILE__\)\)
Run Code Online (Sandbox Code Playgroud)
正则表达式调试器的输出问题:
首先,我在 de 中尝试了我的正则表达式
我认为我对将有效的正则表达式从调试器转换为在 bash/sed 中工作一无所知的基本问题。
我搜索了“如何在 bash 中将 regex 与 sed 一起使用”,但没有找到对这甚至是潜在问题这一事实的解释。
相关问题:为什么没有生成器接受目标字符串作为输入并提供可以找到它的正则表达式?
\$GLOBALS\['\''timechecks'\''\]=addTimeCheck_sparky[(]$GLOBALS
^
Run Code Online (Sandbox Code Playgroud)
那里有一个未逃脱的人$。
\['\''timechecks'\''\][,][ ]number_format[(]microtime[(]true[)]
[,]6[,]'\''\.'\''[,]'\'''\''[)][,][ ]__LINE__[],[ ]basename[(]__FILE__[)][)][;]
^^
Run Code Online (Sandbox Code Playgroud)
那应该是[,]。
不逃避这$甚至无关紧要(至少对于 GNU sed),但这[],[ ]是括号表达式,[],里面有空格。这是一个有效的正则表达式,只是不是你想要的,所以它不会产生任何错误。
但实际上,引用实在是太痛苦了。有时最好避免它。
让我们将模式和替换字符串与测试文件一起放在一些文件中:
$ cat pat
$GLOBALS['timechecks']=addTimeCheck_sparky($GLOBALS['timechecks'], number_format(microtime(true),6,'.',''), __LINE__, basename(__FILE__));
$ cat repl
hello!
$ cat test.txt
foo
$GLOBALS['timechecks']=addTimeCheck_sparky($GLOBALS['timechecks'], number_format(microtime(true),6,'.',''), __LINE__, basename(__FILE__));
bar
Run Code Online (Sandbox Code Playgroud)
然后,用 Perl 替换字符串:
$ pat=$(< pat) repl=$(< repl) perl -i.bak -pe 's/\Q$ENV{pat}/$ENV{repl}/' test.txt
$ cat test.txt
foo
hello!
bar
Run Code Online (Sandbox Code Playgroud)
从文件中读取字符串时,不需要在 shell 命令行上引用。此外,当模式来自变量并被\Q使用时,不需要对模式中的特殊字符进行转义。在这里,我通过环境将字符串传递给 Perl,因为它-i比命令行参数更有效。-pmake 的perl行为有点像sed它为每个输入行运行给定的脚本,-i.bak就像seds -i。
相关问题:为什么没有生成器接受目标字符串作为输入并提供可以找到它的正则表达式?
好。通常正则表达式与旨在匹配多个字符串的模式一起使用,并且程序可能很难知道哪些部分可以改变。尽管如果您一直在寻找固定字符串,那么转义特殊字符会有些简单。但是,您实际上一开始就不需要正则表达式引擎。只是它们在常见的 Unix 工具中无处不在。
您在评论中提到:
想想看,如果一行与此字符串匹配,这就是我需要知道的替换它的全部内容:
$GLOBALS['timechecks']=addTimeCheck_sparky
就像是
sed -- -e 's/^.*GLOBALS..timechecks..=addTimeCheck_sparky.*$/hello/'
Run Code Online (Sandbox Code Playgroud)
可用于与之匹配并替换整行。当然,这也将匹配#GLOBALS_atimecheckses=addTimeCheck_sparky和相关的变体,因为我作弊,只是用.. 但是你明白了。
此外,您始终可以先备份原始文件,然后运行diff original.txt processed.txt以查看任何更改。
对我有用:
sed -- 's/\$GLOBALS\['\''timechecks'\''\]/completely_different_string/g' <<'END'
foo
$GLOBALS['timechecks']=addTimeCheck_sparky($GLOBALS['timechecks'], number_format(microtime(true),6,'.',''), __LINE__, basename(__FILE__));
bar
END
Run Code Online (Sandbox Code Playgroud)
foo
completely_different_string=addTimeCheck_sparky(completely_different_string, number_format(microtime(true),6,'.',''), __LINE__, basename(__FILE__));
bar
Run Code Online (Sandbox Code Playgroud)
这适用于 Mac 上的默认 BSD sed 和 GNU sed。
术语问题:没有“bash sed”。bash 是您的交互式 shell,它也是一种编程语言。sed 是一种不同的编程语言。从 bash 的角度来看,sed 只是在 $PATH 中找到的另一个命令,例如lsorgrep或 ...