Как удалить или заменить все совпадения шаблона из строки в Bash?

Я пытаюсь написать функцию dirname в Bash, чтобы она не использовала никаких внешних команд.

function dirname() {
  local path=$1
  [[ $path =~ ^[^/]+$ ]] && dir=. || {              # if path has no slashes, set dir to .
    [[ $path =~ ^/+$ ]]  && dir=/ || {              # if path has only slashes, set dir to /
      local IFS=/ dir_a i
      read -ra dir_a <<< "$path"                    # read the components of path into an array
      dir="${dir_a[0]}"
      for ((i=1; i < ${#dir_a[@]}; i++)); do        # strip out any repeating slashes
        [[ ${dir_a[i]} ]] && dir="$dir/${dir_a[i]}" # append unless it is an empty element
      done
    }
  }

  [[ $dir ]] && printf '%s\n' "$dir"                # print only if not empty
}

Чтобы удалить любые повторяющиеся / из пути, мне пришлось использовать логику массива. Есть ли более простой способ сделать то же самое с параметром Bash Расширение? Я пытался, но, кажется, у меня не получается.

По сути, я хочу заменить все вхождения нескольких последовательных косых черт одной косой чертой каждый.


person codeforester    schedule 18.10.2017    source источник
comment
Это удалит только последний / и далее. Например: если путь равен a//b//c///d, это даст нам a//b//c//.   -  person codeforester    schedule 18.10.2017
comment
Просто из любопытства, где вы находите такой путь, как a//b//c///d? Единственное, с чем я столкнулся, это преобразование компонентов пути Windows с drive:\\a\\b\\c\\file.ext в POSIX drive:/a/b/c/file.ext. Где вы можете создать путь, подобный a//b//c///d? ветер? Или это просто обычное упражнение раздеть несколько раз '//'?   -  person David C. Rankin    schedule 18.10.2017
comment
Я пытаюсь имитировать команду dirname.   -  person codeforester    schedule 18.10.2017
comment
$ dirname "//a///b////c/d//e.txt" дает "//a///b////c/d". Откуда берется удаление нескольких косых черт? (или я такой толстый, что все еще скучаю по нему?)   -  person David C. Rankin    schedule 18.10.2017
comment
@DavidC.Rankin - ты прав. Команда dirname не удаляет эти косые черты. Не знаю, почему я так подумал.   -  person codeforester    schedule 19.10.2017


Ответы (1)


If extglob is on:

shopt -s extglob

ты можешь это сделать:

printf '%s\n' "${path//\/+(\/)/\/}"

Это использует синтаксис ${var//pattern/replacement} для выполнения глобальной замены.

Шаблон \/+(\/) (с экранированными косыми чертами, потому что / является разделителем), что на самом деле является /+(/) (где +(/) означает "одна или несколько косых черт").

person melpomene    schedule 18.10.2017