zsh:拆分可能没有扩展名的路径
zsh: Splitting a path that may not have an extension
在 zsh
脚本中,我想将路径的文件名部分分成三部分:根、.
分隔符(可能不存在)和扩展名。另一个进程将修改片段并将它们重新组合在一起。
确定输入路径是否有 .
比
预期的。到目前为止,这是我找到的最佳答案:
split=( "${path:r}" "${${path#${path:r}}:+.}" "${path:e}" )
它使用zsh
的r
和e
参数标志来获取根和扩展;
这些部分运作良好。中间部分更神秘的扩展是
本质上是比较路径根和原始路径。如果他们是
相同,则没有分隔符并且该值设置为空字符串。
否则设置为句点。
似乎应该有比三部分嵌套更简单的选择
代换。有没有我遗漏的标志或简单的东西,或者 SO
post 我的搜索没有找到?
测试代码:
#!/bin/zsh
testsplit() {
local path=
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].
It seems there should be an easier option than a three-part nested substitution.
也许吧,但不幸的是,真的没有。
这是我的做法,但同样,无法避免嵌套替换:
% split() {
local split=( ":r" "${${1#:r}[1]}" ":e" )
print "${(q@)split}"
}
% split foo.orig.c
foo.orig . c
% split dir.c/foo
dir.c/foo '' ''
在 zsh
脚本中,我想将路径的文件名部分分成三部分:根、.
分隔符(可能不存在)和扩展名。另一个进程将修改片段并将它们重新组合在一起。
确定输入路径是否有 .
比
预期的。到目前为止,这是我找到的最佳答案:
split=( "${path:r}" "${${path#${path:r}}:+.}" "${path:e}" )
它使用zsh
的r
和e
参数标志来获取根和扩展;
这些部分运作良好。中间部分更神秘的扩展是
本质上是比较路径根和原始路径。如果他们是
相同,则没有分隔符并且该值设置为空字符串。
否则设置为句点。
似乎应该有比三部分嵌套更简单的选择 代换。有没有我遗漏的标志或简单的东西,或者 SO post 我的搜索没有找到?
测试代码:
#!/bin/zsh
testsplit() {
local path=
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].
It seems there should be an easier option than a three-part nested substitution.
也许吧,但不幸的是,真的没有。
这是我的做法,但同样,无法避免嵌套替换:
% split() {
local split=( ":r" "${${1#:r}[1]}" ":e" )
print "${(q@)split}"
}
% split foo.orig.c
foo.orig . c
% split dir.c/foo
dir.c/foo '' ''