Подтвердить что ты не робот

Удалить часть пути в Unix

Я пытаюсь удалить часть пути в строке. У меня есть путь:

/path/to/file/drive/file/path/

Я хочу удалить первую часть /path/to/file/drive и произвести вывод:

file/path/

Примечание. У меня есть несколько путей в цикле while с тем же /path/to/file/drive во всех них, но я просто ищу "как" удалить нужную строку.

Я нашел несколько примеров, но я не могу заставить их работать:

echo /path/to/file/drive/file/path/ | sed 's:/path/to/file/drive:\2:'
echo /path/to/file/drive/file/path/ | sed 's:/path/to/file/drive:2'

\2 является второй частью строки, и я явно делаю что-то неправильно... может быть, есть более простой способ?

4b9b3361

Ответ 1

Вы также можете использовать расширение переменной оболочки POSIX для этого.

path=/path/to/file/drive/file/path/
echo ${path#/path/to/file/drive/}

Часть #.. отбрасывает строку соответствия, когда переменная расширяется; это особенно полезно, если ваши строки уже находятся в переменных оболочки, например, если вы используете цикл for. Вы также можете разделить соответствующие строки (например, расширение) с конца переменной, используя %.... См. Справочную страницу bash для деталей gory.

Ответ 2

Если вы хотите удалить определенное количество компонентов пути, вы должны использовать cut с -d'/'. Например, если path=/home/dude/some/deepish/dir:

Чтобы удалить первые два компонента:

# (Add 2 to the number of components to remove to get the value to pass to -f)
$ echo $path | cut -d'/' -f4-
some/deepish/dir

Чтобы сохранить первые два компонента:

$ echo $path | cut -d'/' -f-3
/home/dude

Чтобы удалить последние два компонента (rev изменит строку):

$ echo $path | rev | cut -d'/' -f4- | rev
/home/dude/some

Чтобы сохранить последние три компонента:

$ echo $path | rev | cut -d'/' -f-3 | rev
some/deepish/dir

Или, если вы хотите удалить все перед конкретным компонентом, sed будет работать:

$ echo $path | sed 's/.*\(some\)/\1/g'
some/deepish/dir

Или после определенного компонента:

$ echo $path | sed 's/\(dude\).*/\1/g'
/home/dude

Это еще проще, если вы не хотите сохранять компонент, который вы указываете:

$ echo $path | sed 's/some.*//g'
/home/dude/

И если вы хотите быть последовательным, вы также можете сопоставить конечную косую черту:

$ echo $path | sed 's/\/some.*//g'
/home/dude

Конечно, если вы соответствуете нескольким чертам, вы должны переключить разделитель sed:

$ echo $path | sed 's!/some.*!!g'
/home/dude

Обратите внимание, что в этих примерах используются абсолютные пути, вам придется поиграть, чтобы они работали с относительными путями.

Ответ 3

Если вы не хотите жестко кодировать часть, которую вы удаляете:

$ s='/path/to/file/drive/file/path/'
$ echo ${s#$(dirname "$(dirname "$s")")/}
file/path/

Ответ 4

Один из способов сделать это с помощью sed -

echo /path/to/file/drive/file/path/ | sed 's:^/path/to/file/drive/::'

Ответ 5

Использование ${path#/path/to/file/drive/}, как было предложено evil otto, безусловно, является типичным/лучшим способом сделать это, но, поскольку существует множество предложений sed, стоит отметить, что sed перегружен, если вы работаете с фиксированной строкой. Вы также можете сделать:

echo $PATH | cut -b 21-

Отбросить первые 20 символов. Аналогично, вы можете использовать ${PATH:20} в bash или $PATH[20,-1] в zsh.

Ответ 6

Если вы хотите удалить первые N частей пути, вы, конечно, можете использовать N вызовов dirname, как в glenn answer, но, вероятно, проще использовать globbing:

path=/path/to/file/drive/file/path/
echo "${path#*/*/*/*/*/}"   #  file/path/

В частности, ${path#*/*/*/*/*/} означает "вернуть $path минус кратчайший префикс, содержащий 5 слешей".

Ответ 7

Чистый Баш, без жесткого кодирования ответа

basenames()
{
  local d="${2}"
  for ((x=0; x<"${1}"; x++)); do
    d="${d%/*}"
  done
  echo "${2#"${d}"/}"
}
  • Аргумент 1 - Сколько уровней вы хотите сохранить (2 в исходном вопросе)
  • Аргумент 2 - Полный путь