我正在尝试删除字符串中的部分路径。我有路径:
/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
是字符串的第二部分,我显然做错了什么......也许有更简单的方法?
如果您想删除特定 NUMBER 的路径组件,您应该将
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-
# output:
# some/deepish/dir
保留前两个组件:
echo $path | cut -d'/' -f-3
# output:
# /home/dude
删除最后两个组件(
rev
反转字符串):
echo $path | rev | cut -d'/' -f4- | rev
# output:
# /home/dude/some
保留最后三个组件:
echo $path | rev | cut -d'/' -f-3 | rev
# output:
# some/deepish/dir
或者,如果您想删除特定组件之前的所有内容,
sed
可以工作:
echo $path | sed 's/.*\(some\)/\1/g'
# output:
# some/deepish/dir
或在特定组件之后:
echo $path | sed 's/\(dude\).*/\1/g'
# output:
# /home/dude
如果您不想保留指定的组件,那就更容易了:
echo $path | sed 's/some.*//g'
# output:
# /home/dude/
如果你想保持一致,你也可以匹配尾部斜杠:
echo $path | sed 's/\/some.*//g'
# output:
# /home/dude
当然,如果您要匹配多个斜杠,则应该切换
sed
分隔符:
echo $path | sed 's!/some.*!!g'
# output:
# /home/dude
请注意,这些示例都使用绝对路径,您必须尝试使它们能够使用相对路径。
您还可以使用 POSIX shell 变量扩展来执行此操作。
path=/path/to/file/drive/file/path/
echo ${path#/path/to/file/drive/}
当变量展开时,
#..
部分会去掉前导的匹配字符串;如果您的字符串已经在 shell 变量中(例如您正在使用 for
循环),这尤其有用。您还可以使用 %...
从变量末尾删除匹配的字符串(例如扩展名)。请参阅 bash
手册页了解血淋淋的细节。
如果您不想对要删除的部分进行硬编码:
$ s='/path/to/file/drive/file/path/'
$ echo ${s#$(dirname "$(dirname "$s")")/}
file/path/
使用 sed 执行此操作的一种方法是
echo /path/to/file/drive/file/path/ | sed 's:^/path/to/file/drive/::'
如果你想删除路径的最后N个组件,你当然可以使用N调用
dirname
,如glenn的答案所示,但使用globbing可能更容易:
path=/path/to/file/drive/file/path/
echo "${path#*/*/*/*/*/}" # file/path/
具体来说,
${path#*/*/*/*/*/}
的意思是“返回$path
减去包含5个斜杠的最短前缀”。
按照邪恶 otto 的建议使用
${path#/path/to/file/drive/}
无疑是执行此操作的典型/最佳方法,但由于有许多 sed 建议,值得指出的是,如果您使用固定字符串,则 sed 是多余的。你还可以这样做:
echo $PATH | cut -b 21-
丢弃前 20 个字符。同样,您可以在 bash 中使用
${PATH:20}
或在 zsh 中使用 $PATH[20,-1]
。
纯粹的 bash,无需硬编码答案
basenames()
{
local d="${2}"
for ((x=0; x<"${1}"; x++)); do
d="${d%/*}"
done
echo "${2#"${d}"/}"
}
取自vsi_common(原始版本)
这里有一个使用简单 bash 语法的解决方案,它可以容纳变量(如果您不想硬编码完整路径),无需将标准输入管道传输到
sed
,并包含一个 for
循环,以达到良好的效果:
FULLPATH="/path/to/file/drive/file/path/"
SUBPATH="/path/to/file/drive/"
for i in $FULLPATH;
do
echo ${i#$SUBPATH}
done
正如 @evil otto 上面提到的,在这种情况下,
#
符号用于删除前缀。