如何替换Bash中的N个重复字符?

时间:2019-06-21 20:37:27

标签: linux string bash replace opensuse

我想将任何特殊字符(不是数字或字母)替换为一个'-'。

我在下面的代码中尝试了一些字符,但是当重复字符超过1次时,它将不起作用,因为仍然会有多个'-'。

#!/bin/bash
for f in *; do mv "$f" "${f// /-}"; done

for f in *; do mv "$f" "${f//_/-}"; done

for f in *; do mv "$f" "${f//-/-}"; done  

我想要什么:

test---file       ->  test-file

test   file       ->  test-file

test______file    ->  test-file

teeesst--ffile    ->  teeesst-ffile

test555----file__ ->  test555-file

请解释您的答案,因为我对bash,regexp不太了解...

2 个答案:

答案 0 :(得分:1)

您可以使用tr(如注释中上面所示),或者实际上,sed在这种情况下更有意义。例如,给定您的文件名列表:

$ cat fnames
test---file
test   file
test______file
teeesst--ffile
test555----file__

您可以使用sed表达式:

sed -e 's/[[:punct:] ][[:punct:] ]*/-/' -e 's/[[:punct:] ]*$//'

使用/输出示例

$ sed -e 's/[[:punct:] ][[:punct:] ]*/-/' -e 's/[[:punct:] ]*$//' fnames
test-file
test-file
test-file
teeesst-ffile
test555-file

根据文件名的存储方式,可以单独使用命令替换,也可以使用进程替换并将更新后的名称输入{{1} }循环或类似的内容。

答案 1 :(得分:1)

在Linux的各种发行版中,有几个不同的rename(或prename)命令可用于处理正则表达式替换。

但是您也可以使用Bash的扩展globing来完成其中的一些操作。模式${var//+([-_ ])/-}表示用一个连字符替换方括号中列出的任何一个或多个字符。

shopt -s extglob
# demonstration:
for file in test---file 'test   file' test______file teeesst--ffile test555----file__
do
    echo "${file//+([-_ ])/-}"
done

输出:

test-file
test-file
test-file
teeesst-ffile
test555-file-

扩展的+()类似于正则表达式中的.+。其他Bash扩展的问题(来自man bash):

          ?(pattern-list)
                 Matches zero or one occurrence of the given patterns
          *(pattern-list)
                 Matches zero or more occurrences of the given patterns
          +(pattern-list)
                 Matches one or more occurrences of the given patterns
          @(pattern-list)
                 Matches one of the given patterns
          !(pattern-list)
                 Matches anything except one of the given patterns

请注意,最后的连字符未在此处删除,但可能使用了附加的参数扩展:

file=${file/%-/}

表示删除字符串末尾的连字符。