如何替换Bash中N个重复的特殊字符?
How to replace N repeated special characters in Bash?
我想将任何特殊字符(不是数字或字母)替换为一个“-”。
我用一些字符尝试了下面的代码,但是当字符重复超过 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、正则表达式...
您可以使用 tr
(如上面的评论所示),或者实际上,sed
在这种情况下更有意义。例如,给定您的文件名列表:
$ cat fnames
test---file
test file
test______file
teeesst--ffile
test555----file__
您可以使用 sed
表达式:
sed -e 's/[[:punct:] ][[:punct:] ]*/-/' -e 's/[[:punct:] ]*$//'
示例Use/Output
$ sed -e 's/[[:punct:] ][[:punct:] ]*/-/' -e 's/[[:punct:] ]*$//' fnames
test-file
test-file
test-file
teeesst-ffile
test555-file
根据文件名的存储方式,您可以单独使用命令替换,也可以使用进程替换并提供将名称更新为 while
循环或类似的东西。
在 Linux 的各种发行版中有几个不同的 rename
(或 prename
)命令可以处理正则表达式替换。
但您也可以使用 Bash 的扩展 globbing 来完成其中的一些工作。模式 ${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-
扩展的 glob +()
类似于正则表达式中的 .+
。其他 Bash 扩展 glob(来自 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/%-/}
表示要删除字符串末尾的连字符。
我想将任何特殊字符(不是数字或字母)替换为一个“-”。
我用一些字符尝试了下面的代码,但是当字符重复超过 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、正则表达式...
您可以使用 tr
(如上面的评论所示),或者实际上,sed
在这种情况下更有意义。例如,给定您的文件名列表:
$ cat fnames
test---file
test file
test______file
teeesst--ffile
test555----file__
您可以使用 sed
表达式:
sed -e 's/[[:punct:] ][[:punct:] ]*/-/' -e 's/[[:punct:] ]*$//'
示例Use/Output
$ sed -e 's/[[:punct:] ][[:punct:] ]*/-/' -e 's/[[:punct:] ]*$//' fnames
test-file
test-file
test-file
teeesst-ffile
test555-file
根据文件名的存储方式,您可以单独使用命令替换,也可以使用进程替换并提供将名称更新为 while
循环或类似的东西。
在 Linux 的各种发行版中有几个不同的 rename
(或 prename
)命令可以处理正则表达式替换。
但您也可以使用 Bash 的扩展 globbing 来完成其中的一些工作。模式 ${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-
扩展的 glob +()
类似于正则表达式中的 .+
。其他 Bash 扩展 glob(来自 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/%-/}
表示要删除字符串末尾的连字符。