数组和 sed WP 配置替换出错

问题描述 投票:0回答:1
newwpuser=$cpuser"_"$wpuser
newwpdb=$cpuser"_"$wpdb
wpdb=($(find . -name "wp-config.php" -print0 | xargs -0 -r grep -e "DB_NAME" | cut -d \' -f 4))
wpuser=($(find . -name "wp-config.php" -print0 | xargs -0 -r grep -e "DB_USER" | cut -d \' -f 4))
wpconfigchanges=($(find . -name wp-config.php -type f))

for i in "${wpconfigchanges[@]}"; do -exec sed -i -e "/DB_USER/s/'$wpuser'/'$newwpuser'/" | -exec sed -i -e "/DB_NAME/s/'$wpdb'/'$newwpuser'/"; done

我正在尝试运行上述命令以查找所有 WordPress 配置并使用 cpuuser_ 附加 db 用户和 dbname

但是 - 我收到以下错误;

./test.sh: line 85: -exec: command not found
./test.sh: line 85: -exec: command not found

我是否输入了错误的exec命令?

执行时输入CPUUser

bash shell automation scripting sh
1个回答
0
投票

确实,

-exec
不是有效命令的名称。目前还不清楚你为什么这么认为,或者你希望它会做什么。

很可能你只是想说……同样的事情,没有

-exec
,也没有疯狂的
sed
管道;

for i in "${wpconfigchanges[@]}"; do
    sed -i -e "/DB_USER/s/'$wpuser'/'$newwpuser'/" \
           -e "/DB_NAME/s/'$wpdb'/'$newwpuser'/" "$i"
done

简单来说,管道

a | b
运行命令
a
b
,使得
a
的输出成为
b
的输入;但如果
a
sed -i
,它不会产生任何输出(它将其写回输入文件);如果
b
sed -i
,则它不会读取其标准输入(它从您在命令行上提供的文件参数中读取)。

您想要的可以表达为两个单独的

sed -i
命令(它们之间只有换行符或分号,而不是管道
|
);但在同一个文件上重复运行
sed -i
是重复的、不优雅的且低效的:打开文件,将所有行复制到临时文件中,对一行进行很小的更改,然后重命名临时文件 - 然后才执行另一个临时文件又发生同样的事情。无论如何,
sed
是一种脚本语言,尽管是一种原始语言;它是专门为一次性执行多个命令而设计的。

您可能会从带有

-exec
的示例中得到
find
,类似

find . -type f \
    -name '*.sh' \
    -exec sed -i '1/s%^!#/bin/bash%!#/bin/sh%' {} \;

...但是在这里,

-exec
(以及
-type
-name
)是控制
find
命令应该执行的操作的选项;我们告诉它在当前目录 (
.
) 及其子目录中搜索与特定命名模式 (
-type f
) 匹配的常规文件(例如,不是目录、符号链接、设备文件等;
-name '*.sh'
);并在找到的文件上执行 (
-exec ... \;
) 特定的命令序列(此处为
sed -i '1/s%^!#/bin/bash%!#/bin/sh%'
{}
占位符指示在命令行上添加文件名的位置;
\;
终止整个参数字符串到
-exec
)。

...但事实上,还是那样做比较好。请注意,您并不真正关心被替换的内容;您只关心被替换的内容。因此,运行

find
两次来查找原始值基本上是多余的,而且很脆弱(如果不同的
wp-config.php
文件具有不同的值怎么办?然后
find
将返回多个字符串的序列,这可能不会发生在您的文件中完全串联 - 即使它们这样做,
sed
也无法处理
s/.../.../
命令中间的换行符)。相反,让我们替换这些行中的第四个字段。

此外,将最后一个

find
的输出收集到数组中很脆弱(该数组将无法正确捕获包含空格的文件名),并且浪费内存(捕获变量中的文件名,这样您就可以简单地循环它们然后立即丢弃它们是完全没用的)。

find
也可能是一个非常昂贵的命令;如果不能保证目录树绝对很小,那么您确实希望避免多次遍历它。

newwpuser=$cpuser"_"$wpuser
newwpdb=$cpuser"_"$wpdb
find . -name wp-config.php \
    -type f -exec sed -i -E \
      -e "/DB_NAME/s/^(([^']*'){3})[^']*/\1$newwpdb/" \
      -e "/DB_USER/s/^(([^']*'){3})[^']*/\1$newwpuser/" {} +

-E
sed
选项(这是非标准的,但如果您也有
-i
的话几乎肯定可用)选择稍微更现代、更通用的正则表达式方言;具体来说,它消除了捕获表达式中括号和大括号之前反斜杠的碍眼。符号
{3}
表示重复前面的正则表达式 3 次,而
[^']*'
则通过下一个单引号向上匹配文本(因此,零个或多个不是单引号的字符后跟单引号)。括号匹配的文本可在
\1
中找到;因此,我们将前三个单引号字段替换为它们自己,然后是新值。根据定义,最后的
[^']*
匹配最长的可能字符串,因此它会延伸到下一个单引号或行尾之前。

顺便说一句,替换文本本身可能看起来很神秘,直到您意识到以这种方式表达搜索可以让我们精确地定位特定字段进行替换。换句话说,这可以推广为s/(锚定前缀)找到这个(锚定后缀)/替换/

这个答案又长又曲折,因为你的脚本有很多复杂之处。展望未来,最好将您的问题简化为“最小可重现示例”,其中包含一个问题,其中代码不能完全满足您的要求(但是每个问题都将是一个相对常见的初学者问题,这些问题已经被解决了)已回答多次;提问前请先搜索)。 你也很不幸,

find

sed
是 shell 生态系统中一些比较阴暗的角落。部分挑战在于这些命令的标准化程度很差,尽管我基本上假设您使用的是 GNU/Linux 系统(例如,MacOS 上的
sed -i
语法会有所不同)。
    

© www.soinside.com 2019 - 2024. All rights reserved.