Как заменить N повторяющихся символов в Bash? - PullRequest
0 голосов
/ 21 июня 2019

Я хочу заменить любой специальный символ (не цифру или букву) на один '-'.

Я попробовал приведенный ниже код с некоторыми символами, но он не работает, когда символ повторяется более 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 ]

1 голос
/ 22 июня 2019

Существует несколько различных команд rename (или prename), доступных в различных дистрибутивах Linux, которые будут обрабатывать подстановки регулярных выражений.

Но вы также можете использовать расширенную глобализацию Bash, чтобы сделать кое-что из этого. Шаблон ${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/%-/}

, который говорит удалить дефис в конце строки.

1 голос
/ 22 июня 2019

Вы можете использовать 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

В зависимости от того, как хранятся ваши имена файлов, вы можете либо использовать подстановка команд по отдельности, либо вы можете использовать подстановка процессов и передавать обновленные имена в цикл whileили что-то подобное.

...