在参数扩展中转义特殊字符

在参数扩展中转义特殊字符
file=/tmp/text/foo.txt

现在我想/bar使用参数扩展语法在此目录结构中添加一个子文件夹。这条线的工作原理:

echo "${file%/*}/bar/${file##*/}"

现在我想知道是否可以通过语法使其更短${parameter/%pat/string}。我想制作/pat,并将其替换为/bar/。但我不知道如何告诉系统哪个/是拍拍部分。我试图用 来逃避它\,但没有成功。我写的代码是:

echo "${f/%///bar/}"

或者

echo "${f/%\///bar/}"

但它们都不起作用。

答案1

使用历史修正

for file in /tmp/text/foo.txt /foo.txt foo.txt mydir/; do
  echo $file:h/bar/$file:t
done

请注意,除了系统上根目录中的文件//some/where不同于/some/where.特别是,如果$file根本没有目录部分,它就可以工作,而天真的版本则${file%/*}没有。如果$file以斜杠结尾,bar则插入到最后一个非空路径组件之前,这可能是也可能不是您想要的。

通过参数扩展形式,您可以使用${VARIABLE/PATTERN/REPLACEMENT}参数扩展标志 I选择第n个匹配项,但不幸的是你无法从最后选择。因此echo ${(I:3:)file/\///bar/}在这种特定情况下有效,但需要确切地知道它们有多少层目录。你可以数一下:

echo ${(I:${#file//[^\/]/}:)file/\///bar/}

但这比拆分成多个部分更复杂,并且如果 中没有斜杠,它也不会更好地工作$file

开启后extended_glob,您可以使用b 通配标志在模式中,这可以让您匹配尾随的非斜杠字符(感谢# 全局运算符) 并用于$match引用通配符匹配的部分。

setopt extended_glob
for file in /tmp/text/foo.txt /foo.txt foo.txt mydir/; do
  echo ${file/%(#b)([^\/]#)/bar/$match[1]}
done

模式为(#b)([^\/]#),匹配尾随的非斜杠字符并将匹配的部分保存在$match[1]. zsh ≥5.9,你可以写,即使关闭${(*)file/%(#b)([^\/]#)/bar/$match[1]}也能工作。extended_glob这并不简单,但它具有鲁棒性的优点:即使对于没有目录部分的文件名的常见情况和根目录中文件的边缘情况,结果也是正确的。mydir/bar/如果$file以斜杠结尾,它会产生,这可能是也可能不是您想要的。

相关内容