2012-06-11 3 views
31

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

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

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

file/path/ 

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

ответ

28

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

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

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

+0

Спасибо ... Да, я использую переменные оболочки для выполнения этого. Обе части - это переменные, которые мне нужно удалить и полный путь. – esausilva

+0

Отлично! Но как я могу использовать это, когда строка идет «из трубы»? – gromit190

+0

@Birger, если строка исходит из трубы, тогда вам нужно получить ее в переменной, чтобы использовать расширение оболочки. Или просто используйте 'sed' в этом случае. –

9

Один из способов сделать это с помощью СЭД является

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

Спасибо. Это хорошо работает – esausilva

+0

Awesome - я понятия не имел, что разделитель sed может быть «:» (двоеточие), а не «/» (косой чертой). Элегантный и отлично работает. – stachyra

+0

Вы можете использовать почти любой разделитель с sed, а не только/и: до тех пор, пока вы согласны. –

18

Если вы не хотите, чтобы жёстко части вы извлекая:

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

Я потратил 2 часа, чтобы посмотреть, как это сделать. и вы были единственным, кто опубликовал способ отображения только имени каталога без жесткого кодирования. Мне нужно было сделать: «find/path/to/file/drive/file/* _ TST -maxdepth 0 -type d» Но я хотел показать только имена каталогов без полного пути. и это сделало это. – Whitecat

+0

@Whitecat - это то, что вы хотели, прочитали «man find», в частности «-printf». Вы можете указать '-printf'% h \ n "'. Просто помните, что он распечатает каталог для каждого подходящего файла, чтобы вы захотели отфильтровать это через «uniq». –

3

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

echo $PATH | cut -b 21- 

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

+0

Спасибо. Я использую ответ злого отто. Часть, которую я хочу удалить, исправлена, но может измениться, если я переведу свой сценарий на другой флажок/другой путь. Таким образом, наличие части, которую я хочу удалить из пути в переменной, делает ее проще, чем подсчет .... но информация, которую вы предоставили, хорошо знать :) – esausilva

2

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

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

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

32

Если вы хотите удалить определенное количество компонентов пути, вы должны использовать 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 

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

+0

Удивительный ответ, в частности двойной трюк 'rev'. Будут повышаться, когда моя головоломка заканчивается завтра. –

+1

отличный, информативный ответ в оригинальном духе Unix и намного лучше, чем {chopsquiggleSquiggle}: только: shellversionyoumaynothave. –

Смежные вопросы