【问题标题】:zsh: Splitting a path that may not have an extensionzsh:拆分可能没有扩展名的路径
【发布时间】:2021-02-15 21:55:50
【问题描述】:

zsh 脚本中,我想将路径的文件名组件分成三部分:根、. 分隔符(可能不存在)和扩展名。另一个过程将修改这些部分并将它们重新组合在一起。

确定输入路径是否有. 比确定输入路径要复杂一些 预期的。到目前为止,这是我找到的最佳答案:

split=( "${path:r}" "${${path#${path:r}}:+.}" "${path:e}" )

它使用zshre 参数标志来获取根和扩展名; 这些部分运作良好。中间组件的更神秘的扩展是 本质上是比较路径根和原始路径。如果他们是 同样,则没有分隔符,并且值设置为空字符串。 否则设置为句点。

似乎应该有一个比三部分嵌套更简单的选项 替代。是否有我缺少的标志或简单的东西,或者一个 SO 我的搜索没有找到的帖子?


测试代码:

#!/bin/zsh
testsplit() {
  local path=$1
  local split=( "${path:r}" "${${path#${path:r}}:+.}" "${path:e}" )

  print "input:    [$path]"
  print "split[${#split}]:" "[${(@)^split}]"

  # tests: does rejoined path match input; is second element '.' or empty
  [[ ${(j::)split} == $path && ${split[2]:-.} == '.' ]]
}
typeset -a testpaths=(
  "base.ext"
  "endsindot."
  "no_ext"
  "/a.b/c.d/e"
  "/a.b/c.d/e."
  "/a.b/c.d/e.f"
  "/has/s p aces  /before . after"
  $"/*/'and?[sdf]\n>\t\tpat.tern[^r\`ty&]///*/notreal.d"
)
integer ecount=0
print '.'
for path in ${testpaths}; do
  testsplit "$path"
  (($?)) && ((++ecount)) && print "=== ERROR ==="
  print '.'
done
print "Error count: [$ecount]."
((ecount)) && print "=== ERRORS FOUND ==="

输出:

.
input:    [base.ext]
split[3]: [base] [.] [ext]
.
input:    [endsindot.]
split[3]: [endsindot] [.] []
.
input:    [no_ext]
split[3]: [no_ext] [] []
.
input:    [/a.b/c.d/e]
split[3]: [/a.b/c.d/e] [] []
.
input:    [/a.b/c.d/e.]
split[3]: [/a.b/c.d/e] [.] []
.
input:    [/a.b/c.d/e.f]
split[3]: [/a.b/c.d/e] [.] [f]
.
input:    [/has/s p aces  /before . after]
split[3]: [/has/s p aces  /before ] [.] [ after]
.
input:    [$/*/'and?[sdf]
>       pat.tern[^r`ty&]///*/notreal.d]
split[3]: [$/*/'and?[sdf]
>       pat.tern[^r`ty&]///*/notreal] [.] [d]
.
Error count: [0].

【问题讨论】:

  • 我不太明白这个要求:假设输入是/a.b/c.d/e你期望什么输出?
  • @user1934428 - 我只需要拆分路径的文件名组件,因此目录包含在根目录中。您的示例将被视为没有扩展名的文件名:split=( '/a.b/c.d/e' '' '' )。我将测试代码的预期输出添加到问题中。

标签: zsh filenames filepath


【解决方案1】:

似乎应该有比三部分嵌套替换更简单的选择。

也许,但不幸的是,真的没有。 ?

我会这样做,但同样不能避免嵌套替换:

% split() { 
  local split=( "$1:r" "${${1#$1:r}[1]}" "$1:e" )
  print "${(q@)split}"
}
% split foo.orig.c 
foo.orig . c
% split dir.c/foo 
dir.c/foo '' ''                                                                                                                                                                     

【讨论】:

  • 感谢您对此进行调查;看起来我们现在被复杂的答案所困扰。我想知道 zsh 团队是否考虑过 :d (dot) 参数标志或类似的东西。我对我的嵌套替换版本有一点偏好,因为该变量只列出了两次,但您的版本可能更容易让人理解。
  • 您可以随时直接在邮件列表中询问开发人员:zsh.sourceforge.net/Arc/mlist.html
  • 因为长度/重复是你关心的问题,我现在稍微缩短了代码。 :)
  • 这是我现在最喜欢的版本 - 更少的重复,并且它不对分隔符做任何假设(尽管我们知道它总是.)。谢谢!
猜你喜欢
  • 2012-06-21
  • 1970-01-01
  • 2015-12-20
  • 1970-01-01
  • 1970-01-01
  • 2011-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多