bash: extracting last two dirs for a pathname

前端 未结 7 978
灰色年华
灰色年华 2021-02-12 12:42

I seem to have failed at something pretty simple, in bash. I have a string variable that holds the full path to a directory. I\'d like to assign the last two di

7条回答
  •  忘掉有多难
    2021-02-12 13:15

    DIRNAME="/a/b/c/d/e"
    D2=$(dirname "$DIRNAME")
    DIRNAME2=$(basename "$D2")/$(basename "$DIRNAME")
    

    Or, in one line (but be careful with all the double quotes — it is easier when it is split up):

    DIRNAME2=$(basename "$(dirname "$DIRNAME")")/$(basename "$DIRNAME")
    

    Don't try that game with back-quotes unless you're heavily into masochism. And if there might be spaces in the paths, use double quotes around the variable names.

    This will work with almost any shell Korn Shell as well as Bash. In bash, there are other mechanisms available - other answers illustrate some of the many options, though expr is also an old-school solution (it was present in 7th Edition Unix too). This code using back-quotes works in Bash and Korn shell too — but not in Heirloom Shell (which is similar to a Unix System V Release 2/3/4 shell, IIRC).

    DIRNAME2=`basename "\`dirname \\"$DIRNAME\\"\`"`/`basename "$DIRNAME"`
    

    (Two levels of nesting is not too awful, but it is pretty bad; three gets really tricky!)

    Testing

    When testing path name manipulation that should survive spaces in the path name, it is worth testing with a name containing double-spaces (rather than, or as well as, single spaces). For example:

    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]]"
    

    The output from that is:

    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  ]]
    

提交回复
热议问题