ksh 参数扩展:将 / 替换为 -

ksh 参数扩展:将 / 替换为 -

假设我有这个:

str="@test/string"
echo $str
@test/string
echo ${str#@}
test/string

按预期工作,但是

echo ${str//\//-}
ksh: ${str//\//-}: bad substitution

失败。 (预期@test-string)

像这样替换/替换字符的正确方法是什么?


echo $KSH_VERSION
KSH version @(#)PD KSH v5.2.14 99/07/13.2

答案1

Yes${var//pattern/replacement}是一个 ksh93 操作符,而 pdksh 旨在作为原始 ksh 的克隆,其最后一个版本是 ksh88i1。 pdksh 作为一个项目已经停止,但它仍然存在,因为它是sh少数 BSD 的一部分,包括 OpenBSD 和 MirBSD。 MirBSD sh/ksh 也称为 mksh,也作为便携式 shell 维护,并且在许多 Linux 发行版中可用(甚至在 Android 上使用sh)。它确实在 2008 年的 R33 版本中添加了 ksh93 运算符。

POSIXly,要将变量中的一个字符替换为另一个字符,您可以使用transliterator 实用程序,但您需要在其 stdin 上提供变量的内容并从其 stdout 获取结果:

newstr=$(printf %s "$str" | tr / -; echo .)
newstr=${newstr%.}

(添加的内容.\n是为了解决命令替换会删除尾随换行符的事实)。

您还可以使用 split+glob 运算符来避免运行单独的命令:

IFS=/ # split on /
set -o noglob # disable the glob part
set -- $str'' # split+glob by leaving $str unquoted
IFS=. # join on . in "$*"
newstr="$*"

1 虽然 ksh93 是一个不完全向后兼容的重写,但具有许多新功能,其中许多仍处于实验阶段,并且在其代码在 2000 年代作为开源发布之前很少使用

答案2

shellpdksh是 OpenBSD 等新用户的默认 shell,没有您提到的非标准参数替换。

要将某些模式的所有非重叠匹配替换为某个新字符串,您可以使用sed

str=$( printf '%s\n' "$str" | sed 's/PATTERN/REPLACEMENT/g' )

请注意,这用作PATTERNPOSIX 基本正则表达式,REPLACEMENT必须转义&\1以及将以特殊方式解释的其他字符串sed,并且命令替换会从字符串末尾删除所有尾随换行符。

例子:

$ str=@title/section1/section2
$ str=$( printf '%s\n' "$str" | sed 's/\//-/g' )
$ printf '%s\n' "$str"
@title-section1-section2

在这种情况下,当仅替换单个字符时,可以将替换替换sedy/\//-/,或将整个sed命令替换为tr命令tr / -

您还可以选择编写 shell 循环:

while true; do
    case $str in
        *PATTERN*)
            str=${str%%PATTERN*}REPLACEMENT${str#*PATTERN}
            ;;
        *)
            break
    esac
done

在此代码中,PATTERN是一个 shell 模式(“文件名通配模式”)。该代码重复使用替换字符串替换字符串中模式的第一个匹配项,直到不再有匹配项。由于循环的存在,无法保证后续迭代不会在先前插入的替换字符串中执行替换。

例子:

$ str=@title/section1/section2
$ while true; do case $str in (*/*) str=${str%%/*}-${str#*/} ;; (*) break; esac; done
$ printf '%s\n' "$str"
@title-section1-section2

答案3

肯定是更好的方法,但是:

$(echo "$str" | tr '/' '-')

相关内容