I want to replace any special character (not a number or letter) to one single '-'.
I tried the code below with some characters, but it doesn't work when the character is repeated more than 1 time because would still have more than one '-'.
#!/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
what I want:
test---file -> test-file
test file -> test-file
test______file -> test-file
teeesst--ffile -> teeesst-ffile
test555----file__ -> test555-file
Please, explain your answer because I don't know much about bash, regexp...
There are a couple of different rename
(or prename
) commands available in various distributions of Linux what will handle regex substitutions.
But you can also use Bash's extended globbing to do some of that. The pattern ${var//+([-_ ])/-}
says to replace any runs of one or more characters that are listed in the square brackets with one hyphen.
shopt -s extglob
# demonstration:
for file in test---file 'test file' test______file teeesst--ffile test555----file__
do
echo "${file//+([-_ ])/-}"
done
Output:
test-file
test-file
test-file
teeesst-ffile
test555-file-
The extended glob +()
is similar to .+
in regex. Other Bash extended globs (from 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
Note that the final hyphen is not removed here, but could be using an additional parameter expansion:
file=${file/%-/}
which says to remove a hyphen at the end of the string.
You can use tr
(as shown above in the comment) or, actually, sed
makes more sense in this case. For example, given your list of filenames:
$ cat fnames
test---file
test file
test______file
teeesst--ffile
test555----file__
You can use the sed
expression:
sed -e 's/[[:punct:] ][[:punct:] ]*/-/' -e 's/[[:punct:] ]*$//'
Example Use/Output
$ sed -e 's/[[:punct:] ][[:punct:] ]*/-/' -e 's/[[:punct:] ]*$//' fnames
test-file
test-file
test-file
teeesst-ffile
test555-file
Depending on how your filenames are stored, you can either use command substitution individually, or you can use process substitution and feed the updated names into a while
loop or something similar.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.