2011-11-22 46 views
9

我似乎沒有在bash中很簡單的東西失敗。我有一個字符串變量,保存目錄的完整路徑。我想將其中的最後一個兩個目錄分配給另一個字符串。舉例來說,如果我有:bash:提取路徑名的最後兩個dirs

DIRNAME = /a/b/c/d/e 

我想:

DIRNAME2 = d/e 

我敢肯定有一個簡單的bash結構或sed命令,將做到這一點,但它逃避我。我有點像basenamedirname的廣義版本,不只是返回名稱的極端部分。

謝謝! 戴夫

+1

我只是把基本名稱和基本名稱目錄名稱的並結合了。 –

回答

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

,或者在一個行:

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

,除非你是大舉進入受虐狂不要嘗試遊戲的反引號。如果路徑中可能有空格,請在變量名稱周圍使用雙引號。

這將適用於幾乎所有的shell(即使是第七版Unix Bourne shell - 如果你終究沉迷於使用反引號的受虐狂)。在bash中,還有其他可用的機制 - 其他答案說明了許多選項中的一些,但expr也是一個老派解決方案(它也出現在第7版Unix中)。

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

(兩個嵌套層次是不是太可怕了;三是得到棘手!)

+0

哇,這是我在stackoverflow上的第一篇文章,我對這些回覆非常滿意!我去了/你的一行basename-dirname答案,因爲這只是一個腳本,我將作爲提交數字作業的一部分運行。但是我會保存這個線程以獲得許多華麗的bash字符串技巧! – user1059256

+0

+1,這是最多的語義解決方案。 – harpo

1

我覺得有使用水珠較短的方式,但:

$ DIRNAME='a/b/c/d/e' 
$ LAST_TWO=$(expr "$DIRNAME" : '.*/\([^/]*/[^/]*\)$') 
$ echo $LAST_TWO 
d/e 
2

我不知道的方法專門爲微調路徑,但你肯定能做到這一點與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 

注意:爲了處理路徑中的一些允許但不常見的東西,我在這裏將模式設置得比您想象的複雜一點:它修剪尾部斜槓並容忍多個(冗餘)斜槓最後兩名之間ES。例如,在「/ a/b/c // d //」上運行它將匹配「c // d」。

-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="https://stackoverflow.com/a/b/c/d/e" 
dir2=`getDir $dir 1` 
echo $dir2 

您可以從上次從這個函數得到任何數量的目錄。 對於您的情況下運行它,

dir2=`getDir $dir 2`; 

輸出:/ d/E

1
DIRNAME="a/b/c/d/e" 
DIRNAME2=`echo $DIRNAME | awk -F/ '{print $(NF-1)"_"$(NF)}'` 

DIRNAME2 then has the value d_e 

切換到任何你想下劃線。

8

我更喜歡盡我所能地使用builtins,以避免創建不必要的進程。因爲你的腳本可能在Cygwin或其他操作系統下運行,而這些操作系統的創建過程非常昂貴。

我覺得它不是那麼漫長,如果你只是想提取2個迪爾斯:

base1="${DIRNAME##*/}" 
dir1="${DIRNAME%/*}" 
DIRNAME2="${dir1##*/}/$base1" 

這也可避免參與執行其他命令的特殊字符的問題。

+1

+1最佳解決方案恕我直言。 – helpermethod

0
dirname=/a/b/c/d/e 
IFS=/ read -a dirs <<< "$dirname" 
printf "%s/%s\n" "${dirs[-2]}" "${dirs[-1]}"