在bash中,我似乎在一些非常简单的事情上失败了。我有一个字符串变量,它包含目录的完整路径。我想将最后的两个目录分配给另一个字符串。例如,如果我有:
DIRNAME = /a/b/c/d/e
我想:
DIRNAME2 = d/e
我确信有一个简单的bash构造或sed
命令会执行它,但它正在逃避我。我有点像basename
或dirname
的通用版本,它不仅仅返回名称的极端部分。
谢谢! 戴夫
答案 0 :(得分:12)
DIRNAME="/a/b/c/d/e"
D2=$(dirname "$DIRNAME")
DIRNAME2=$(basename "$D2")/$(basename "$DIRNAME")
或者,在一行中(但要小心所有双引号 - 分割时更容易):
DIRNAME2=$(basename "$(dirname "$DIRNAME")")/$(basename "$DIRNAME")
除非你严重受虐狂,否则不要尝试使用背引号的游戏。如果路径中可能有空格,请在变量名称周围使用双引号。
这几乎适用于任何shell Korn Shell以及Bash。在bash
中,还有其他可用的机制 - 其他答案说明了一些选项,尽管expr
也是一个老派的解决方案(它也出现在第7版Unix中)。这个使用反引号的代码也适用于Bash和Korn shell - 但不适用于Heirloom Shell(类似于Unix System V Release 2/3/4 shell,IIRC)。
DIRNAME2=`basename "\`dirname \\"$DIRNAME\\"\`"`/`basename "$DIRNAME"`
(两个级别的嵌套并不太糟糕,但它非常糟糕;三个非常棘手!)
当测试应该在路径名中的空格中存在的路径名操作时,值得测试使用包含双空格(而不是单个空格)的名称。例如:
DIRNAME="/a b/ c d / ee ff / gg hh "
echo "DIRNAME=[[$DIRNAME]]"
echo "basename1=[[$(basename "$DIRNAME")]]"
echo "basename2=[[`basename \"$DIRNAME\"`]]"
echo
D2=$(dirname "$DIRNAME")
echo "D2=[[$D2]]"
DIRNAME2=$(basename "$D2")/$(basename "$DIRNAME")
echo "DIRNAME2=[[$DIRNAME2]]"
echo
DIRNAME3=$(basename "$(dirname "$DIRNAME")")/$(basename "$DIRNAME")
echo "DIRNAME3=[[$DIRNAME3]]"
DIRNAME4=`basename "\`dirname \\"$DIRNAME\\"\`"`/`basename "$DIRNAME"`
echo "DIRNAME4=[[$DIRNAME2]]"
该输出是:
DIRNAME=[[/a b/ c d / ee ff / gg hh ]]
basename1=[[ gg hh ]]
basename2=[[ gg hh ]]
D2=[[/a b/ c d / ee ff ]]
DIRNAME2=[[ ee ff / gg hh ]]
DIRNAME3=[[ ee ff / gg hh ]]
DIRNAME4=[[ ee ff / gg hh ]]
答案 1 :(得分:10)
我更喜欢尽可能多地使用内置函数,以避免创建不必要的进程。因为您的脚本可能在Cygwin或其他过程创建非常昂贵的操作系统下运行。
如果您只想提取两个目录,我认为这不是很长:
base1="${DIRNAME##*/}"
dir1="${DIRNAME%/*}"
DIRNAME2="${dir1##*/}/$base1"
这也可以避免执行其他命令时遇到的特殊字符问题。
答案 2 :(得分:3)
我不知道专门用于修剪路径的方法,但您当然可以使用bash's regular expression matching执行此操作:
DIRNAME=/a/b/c/d/e
if [[ "$DIRNAME" =~ ([^/]+/+[^/]+)/*$ ]]; then
echo "Last two: ${BASH_REMATCH[1]}"
else
echo "No match"
fi
注意:为了处理路径中允许但不常见的事情,我在这里使模式比你想象的要复杂一点:它修剪尾部斜杠,并容忍多个(冗余)斜杠在最后两个名字之间。例如,在“/ a / b / c // d //”上运行它将匹配“c // d”。
答案 3 :(得分:2)
我认为使用globs的方式较短,但是:
$ DIRNAME='a/b/c/d/e'
$ LAST_TWO=$(expr "$DIRNAME" : '.*/\([^/]*/[^/]*\)$')
$ echo $LAST_TWO
d/e
答案 4 :(得分:2)
DIRNAME="a/b/c/d/e"
DIRNAME2=`echo $DIRNAME | awk -F/ '{print $(NF-1)"_"$(NF)}'`
DIRNAME2 then has the value d_e
将下划线更改为您想要的任何内容。
答案 5 :(得分:1)
dirname=/a/b/c/d/e
IFS=/ read -a dirs <<< "$dirname"
printf "%s/%s\n" "${dirs[-2]}" "${dirs[-1]}"
答案 6 :(得分:-1)
function getDir() {
echo $1 | awk -F/ '
{
n=NF-'$2'+1;
if(n<1)exit;
for (i=n;i<=NF;i++) {
printf("/%s",$i);
}
}'
}
dir="/a/b/c/d/e"
dir2=`getDir $dir 1`
echo $dir2
您可以从此函数的最后一个目录中获取任意数量的目录。 对于你的情况,运行它,
dir2=`getDir $dir 2`;
输出:/ d / e