我正在编写一个脚本,该脚本允许我通过 ssh 从服务器中删除旧公钥。问题似乎出在我的 ssh 命令的格式上:
ssh -qo ConnectTimeout=20 "${user_ssh}@${ip}" "sed -ein \"s|ssh-rsa\s${fingerprint}\s\(.*\)|#---> deleted by public-key-remover.sh. USER:\1|g\" $key_dir || exit 67"
$fingerprint 是 rsa 公钥的指纹。
$key_dir 是公钥文件的位置。
我确保 $key_dir 确实存在但它仍然打印出以下错误:
sed: can't read s|ssh-rsa\sAAAAB3NzaC1yc2EAAAADAQABAAABAQCDlMyH7CX5ckyspCDx8pqzLv41OM0xjlrSeHhi8gz+6jXepaWDtcrlGzkieN3oOK+uUJKT5Jz8uSRBoTfr20tTLLHklRASoWiy7EvACwqfClRVnC67KBWKWlsIDLBGC3KDkJQbYD8ovDP6svy7xBMW0J1RWnQW/RqaCZ9udFMzh5KUbCCm360eVNnFq7fAR//ZeUHNlTGFfSl/WfxkjacAAfKGjtnxYHfo8N/IGP9rbGoX/nlU8XOr2y9uHkVHt+ghG8/wnZo1quUua8JbjMOv6Ygu40Qe9E5pXKOZr1v1RkvMrNOoZ9O8KNvVt7L5+0TvM2NG7AK51qo9ZpHNPr2b\s\(.*\)|#---> deleted by public-key-remover.sh. USER:\1|g: No such file or directory
由于我对 Bash 还很陌生,所以我需要一些帮助。
答案1
主要问题
这里的主要问题是,-e
insed -ein …
是一个需要选项参数(要执行的 sed 脚本)的选项。in
恰好是一个有效的 sed 脚本,并被当作有效脚本。 随后的内容将被解释为要处理的文件的路径。 就好像远程端的命令是 一样sed -e in …
。
我不确定这是否是唯一的问题,但我确信这就是你sed
被解释s|ssh-rsa…
为路径的原因。
如果您想要以紧凑的形式传递-n
和选项,那么必须是最后一个,因为它需要一个选项参数(不需要)。选项参数(即您的 sed 脚本)必须紧跟在后面:-e
-e
-n
sed -i -ne …
我将其分开,-i
因为-isomething
具有含义(可能与不同-i something
)并且您显然不希望它在这里,您想要-i
。
一种直接的方法是逐个指定选项:
sed -i -n -e …
但我真的怀疑你是否想要-n
。你的 sed 脚本没有明确打印任何内容,因此 with-n
不会有任何效果。这意味着-i -n
你的 sed 脚本将清除文件的内容。
注意,如果您尝试了sed -e -i …
,sed
则会抱怨-
这是未知命令,这与您所得到的错误完全不同。这是因为-i
不是有效的 sed 脚本,而您in
意外地 是。
更广阔的前景
我们在这里可以观察到一些惯例:
-n
选项sed
既不需要也不接受选项参数,另一个选项可以跟n
在以 开头的单个参数中-
。sed -nwhatever
相当于, 的含义取决于 的sed -n -whatever
含义。对于不需要选项参数的选项来说, 的约定很常见。-whatever
-w
sed
-abc
-a -b -c
-e
选项sed
需要选项参数。sed -ewhatever
相当于sed -e whatever
。 对于需要选项参数的选项,这种约定相当常见。-i
GNU 的选项sed
可以接受也可以不接受选项参数。当您想要指定一个时,您需要将其与 连接起来-i
。-iwhatever
不等同于-i whatever
也不等同于-i -whatever
。这种约定并不常见。请注意 选项不可移植。sed
您使用的 可能是也可能不是 GNUsed
。比较此线程:sed -i
空参数兼容性问题。不幸的是,这是 GNU sed 扩展,其使用本质上不是可移植的。FreeBSD 的使用与此
-i
类似,但略微不兼容。POSIX-i
未指定该选项,因此根据定义,对它的任何使用都是非标准的。-n
并且-e
由 POSIX 指定。
可能还有其他惯例。不幸的是,手册很少有助于了解哪种工具遵循这种类型的惯例。通常,遵循常见惯例的好工具不会费心(在手册中)说明它们遵循惯例,可能是因为“每个人都应该遵循,这是显而易见的”。而不太好的工具通常不会费心说明它们不遵循,因为它们不在乎;如果他们在乎,他们首先就会遵循。这是我的印象,我的猜测。然后有些工具甚至不遵循以破折号开头选项的惯例(出于各种原因)。
man sed
我的观点是,你可以从、man ls
或中学习相应的选项,但你可以做或的man du
事实并没有明确记录ls -hls
du -hms
那里. 了解常见惯例,尝试使用对您来说很新的工具。许多人会遵循,有些人可能不会(或不会完全遵循)。如有疑问,请将选项指定为单独的参数。
边注
的某些值$key_dir
会有问题。请记住,远程 shell 将再次解释整个字符串(如果$key_dir
扩展为带有空格的字符串会怎样?或者带有????"
)。如果您的本地 shell 是 Bash,则使用。Bash 将以特殊方式扩展变量,因此在(远程)shell 中解析结果后,它会再次变为原始字符串。扩展的字符串被正确引用和/或转义。'
$(reboot)
${key_dir@Q}
答案2
sed选项-i
采用备份文件的扩展名,因此不要将该选项与其他选项捆绑在一起。
另外,-n
停止 sed 打印行,因此您最终会得到一个空文件。
嵌入的反斜杠应当被转义。
该-E
选项意味着括号不需要转义。
尝试一下(使用额外的换行符来增加可读性)
ssh -qo ConnectTimeout=20 "${user_ssh}@${ip}" "
sed -i -E 's|ssh-rsa\\s${fingerprint}\\s(.*)|#---> deleted by public-key-remover.sh. USER:\\1|g' '$key_dir' || exit 67
"