Удалить часть пути в 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
является второй частью строки, и я явно делаю что-то неправильно... может быть, есть более простой способ?
Ответы
Ответ 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 - Полный путь