使用多个字符作为分隔符分割字符串的 ZSH 语法

使用多个字符作为分隔符分割字符串的 ZSH 语法

我找不到使用 ZSH 内置拆分运算符执行此操作的正确语法:https://zsh.sourceforge.io/Guide/zshguide05.html

这有效,但我试图摆脱 echo / sed

for i in *;
do f=$(echo $i | sed 's/[-.]/ /g');
parts=(${(s: :)f}); echo $parts[1]; done

如何在表达式中指定字符集parts=(${(s: :)f});

我试图找到输入字符串的第一个字母数字子字符串。

答案1

s[sep] 参数扩展标志只接受一个字符串(不必是单个字符),而不是一个模式。

您可以s通过以下方式组合多个运算符嵌套扩展:

for file in *(N); do
  parts=( ${(@s[-])${(s[.])file}} )
  print -r The first part is $parts[1]
done

(另请注意(N) 全局限定符以避免当前工作目录中没有非隐藏文件时出现错误)。

或者你可以使用IFS 拆分为$=var1:

IFS=.-
parts=( $=file )

请注意, whileparts=( ${(s[.])string} )会丢弃空元素,IFS=.; parts=( $=string )但不会,尽管您可以parts=($=string); parts=($string)事后丢弃它们或使用匿名函数,例如(){ parts=($@); } $=string.

或者,当您将所有字符替换为 1 并使用s[sep]或 IFS 分割对其进行分割时,尽管您可以使用 ksh 样式${param//pattern/replacement}或 csh 样式(使用histsubstpattern在)$param:gs/pattern/replacement/

parts=( ${(s[.])file//[-...]/.} )

如果这只是您需要的第一个部分,您可以这样做:

first_part=${file%%[.-]*}

就像 ksh 中的语法来自 80 年代。

如果它是一个或多个alnums的第一个序列:

set -o extendedglob
first_sequence_of_alnums=${(MS)file##[[:alnum:]]##}

或者

if [[ $file =~ [[:alnum:]]+ ]]; then
  first_sequence_of_alnums=$MATCH
else
  print -ru2 "There are no alnums in $file"
fi

或者:

alnum_sequences=( ${(s[:])file//[^[:alnum:]]/:} )
if (( $#alnum_sequences > 0 )); then
  first_sequence_of_alnums=$alnum_sequences[1]
else
  print -ru2 "There are no alnums in $file"
fi

无论如何,如果你必须使用echo,这应该是

echo -E - $file

如果没有-E,反斜杠$file可能会被破坏。如果没有,这对于诸如...之类-的值不起作用$file-n -Eneeneprintprint -r -- $file(或者print -r - $file)。更重要的是不要忘记--/-printasprint支持更多选项,其中一些可能存在危险。


1 请注意这是其他类似 Bourne 的 shell 在未加引号的参数扩展时默认执行的操作之一,通常被认为是一个错误特征(并且危险的一个!)。在 zsh 中,您必须显式请求分割,$=var就像您必须显式请求通配符一样(也在其他 shell 中的未加引号的扩展上完成!)$~var(或$=~var两者)。

相关内容