sed:无法使用变量替换最新出现的文本,包括“-”破折号
Posted
技术标签:
【中文标题】sed:无法使用变量替换最新出现的文本,包括“-”破折号【英文标题】:sed: Can't replace latest text occurrence including "-" dashes using variables 【发布时间】:2022-01-20 19:21:29 【问题描述】:尝试用 sed 使用变量将文本替换为另一个文本。在变量的内容包含破折号“-”并且 sed 尝试解释它之前,它工作得很好。
需要注意的是,在这种情况下,我只需要替换最近出现的原始变量 $src,这就是为什么我的 sed 命令看起来像这样:
sed -e "s:$source([^$source]*)$:$dest\1:"
“sed”对我来说是一种新事物,我总是尽可能使用“replace”或“awk”来获得结果,但在这里我试图使代码尽可能多才多艺,因此使用 sed。如果您想到其他解决方案,那也是可行的。
问题示例:
# mkdir "/home/youruser/TEST-master"
# source="TEST-master" ; dest="test-master" ; find /home/youruser/ -depth -type d -name '*[[:upper:]]*' | grep "TEST" | sed -e "s:$source([^$source]*)$:$dest\1:"
sed: -e expression #1, char 46: Invalid range end
鉴于我不知道每个变量可能包含多少个破折号,是否有任何 sed 专家知道我该如何进行这项工作?
确切的上下文:我正在为其重写一个函数以递归地小写文件和目录的开源项目 LinuxGSM。 我正在处理的 Bash 函数并在这里发表评论:https://github.com/GameServerManagers/LinuxGSM/issues/1868#issuecomment-996287057
【问题讨论】:
这不仅会在 $source 包含破折号时出错,而且还会在其他特殊字符(如括号)时出错,尤其是当有分隔符时(在您的情况下为“:”)。所以我建议用另一个 sed 转义这些字符,或者(更好的恕我直言)恢复为 awk。 括号表达式[^xyz]
匹配除x
、y
或z
之外的任何单个字符。这并不意味着除xyz
之外的任何字符串(您似乎认为它确实如此)。括号表达式始终匹配单个字符(该字符是括号之间的列表中表示的集合的成员)。
【参考方案1】:
如果我正确理解上下文,实际目标是采用在其最后一个元素中包含一些大写字符的路径,并创建一个最后一个元素小写的版本。例如,/SoMe/PaTh/FiLeNaMe
将转换为 /SoMe/PaTh/filename
。如果是这种情况,不要使用字符串替换,而是使用 dirname
和 basename
将其拆分为组件,最后一个大写,然后重新组装:
parentdir=$(dirname "$src")
filename=$(basename "$src")
lowername=$(echo "$latestpath" | tr '[:upper:]' '[:lower:]')
dst="$parentdir/$lowername"
(旁注:将参数引用到tr
很重要,以确保shell 不会将它们视为文件名通配符并将它们替换为匹配文件的列表。)
只要路径包含至少一个“/”但不以“/”结尾,您就可以使用 bash 替换来代替 dirname
和 basename
:
parentdir="$src%/*"
filename="$src##*/"
只要您使用的是 bash v4.0 或更高版本,您还可以使用内置替换来进行小写:
lowername="$filename,,"
【讨论】:
你的回答是天才级别的,谢谢!当然,总有更好的方法可以在没有 sed 和避免问题的情况下做任何事情!我不知道我之前怎么没有想到你的第一个解决方案,它要简单得多!第二个换人也很棒。我会重写函数并报告。 完全重写了函数,PR 在路上。再次感谢您的提醒。在这样的时刻热爱社区! github.com/GameServerManagers/LinuxGSM/pull/3717以上是关于sed:无法使用变量替换最新出现的文本,包括“-”破折号的主要内容,如果未能解决你的问题,请参考以下文章