我有许多不同的文件,其中包含一个字符串。我需要用路径替换此字符串,尽管路径包含空格。到目前为止,我有以下内容:
for a in files_[a-z][a-z]_all\.conf ; do
fileWithPath="~/Downloads/files_config_linux/auth-user-pass files_userpass.txt"
otherOne="auth-user-pass mullvad_userpass.txt"
sed -i 's|'$otherOne'|'$fileWithPath'|g' $a
done
但我明白
sed:-e 表达式 #1,字符 16:未终止的“s”命令
我的问题是如何用带有空格的路径正确地替换该字符串。
谢谢!
答案1
你的表情
's|'$otherOne'|'$fileWithPath'|g'
产生不带引号的字符串
s|auth-user-pass mullvad_userpass.txt|~/Downloads/files_config_linux/auth-user-pass files_userpass.txt|g
然后根据空格字符将其解析为几个单词。第一个单词是
s|auth-user-pass
然后传递给sed
正确抱怨缺少第二个|
分隔符。
要将整个s
命令sed
作为单个参数传递,您需要将其括起来。最简单的方法是将整个表达式括在双引号中:
"s|$otherOne|$fileWithPath|g"
shell 在双引号内执行变量替换,因此这将产生带引号的字符串
"s|auth-user-pass mullvad_userpass.txt|~/Downloads/files_config_linux/auth-user-pass files_userpass.txt|g"
sed
然后将其作为单个参数按预期传递。
将文件名参数括在双引号中也是很好的做法$a
,这样可以防止文件名中出现空格,但对于您来说这并不是绝对必要的,因为您的模式files_[a-z][a-z]_all\.conf
不会匹配任何包含空格的文件名。
答案2
你的壳会裂开未引用字符串(在您的情况下由参数/变量扩展产生)到值周围的单词IFS
...参见单词拆分...那是一回事。
您的 shell 可能会将带有修改过的引号的命令行参数传递给被调用的程序……这是另一回事。
他们说“亲眼看见一次胜过听到一百次。“和“做一次胜过看一百次。“...
如果您在 Bash shell 中启用命令跟踪set -x
,然后sed
按照以下方式发出命令:
$ set -x
$
$ fileWithPath="~/Downloads/files_config_linux/auth-user-pass files_userpass.txt"
$ otherOne="auth-user-pass mullvad_userpass.txt"
$
$ sed -i 's|'$otherOne'|'$fileWithPath'|g'
+ sed -i 's|auth-user-pass' 'mullvad_userpass.txt|~/Downloads/files_config_linux/auth-user-pass' 'files_userpass.txt|g'
sed: -e expression #1, char 16: unterminated `s' command
...您可以看到您的命令行实际上是如何构建并传递给程序的sed
,并且正如您所看到的,您提供的脚本被分解为多个部分(添加了引号)...并且就程序而言,sed
只有第一组匹配的引号被视为脚本's|auth-user-pass'
,并且由于没有提供,因此以下引号甚至不被视为或添加到脚本中-e
(以指示嵌套命令,尽管-e
需要语法正确的命令才能工作),因此,事实上,该s
命令并没有在该上下文中终止......因此出现以下消息:
sed:-e 表达式 #1,字符 16:未终止的“s”命令
现在,您可以看到幕后情况,将上述内容与以下内容进行比较:
$ sed -i 's|'"$otherOne"'|'"$fileWithPath"'|g'
+ sed -i 's|auth-user-pass mullvad_userpass.txt|~/Downloads/files_config_linux/auth-user-pass files_userpass.txt|g'
sed: no input files
或者:
$ sed -i "s|$otherOne|$fileWithPath|g"
+ sed -i 's|auth-user-pass mullvad_userpass.txt|~/Downloads/files_config_linux/auth-user-pass files_userpass.txt|g'
sed: no input files
...这应该足以通过“观察”和“行动”来弄清楚到底发生了什么。