2011-11-22 11 views
9

私はbashのなかでかなり単純に失敗したようです。私は、ディレクトリへの完全なパスを保持する文字列変数を持っています。最後にの2つのディレクトリを別の文字列に割り当てたいと思います。例えば、私が持っている場合:bash:パス名の最後の2つのディレクトリを抽出する

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

は、私が欲しい:

DIRNAME2 = d/e 

私はそれを行います簡単なbashの構築物またはsedコマンドがあります確信しているが、それは私をエスケープています。私はbasenameまたはdirnameという一般化されたバージョンのようなもので、名前の極端な部分を返すだけではありません。

ありがとうございます! デイブ

+1

私はbasenameのベース名とdirnameをとり、それらを戻して組み合わせて返します。 –

答えて

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

あるいは、1行に:あなたはマゾヒズムに重くない限り

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

バック引用符でそのゲームをしようとしないでください。パスにスペースがある場合は、変数名の前後に二重引用符を使用してください。

これはほぼすべてのシェル(たとえ、バッククォートを使用することの奇妙なことに夢中ならば、第7版のUnix Bourneシェルでさえ)でも動作します。 bashには、利用可能な他のメカニズムがあります。exprも古い学校のソリューションです(これは第7版のUnixでも提供されていますが)。

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

(ネスティングの2つのレベルがあまりにもひどいではありません。3はトリッキー取得!)

+0

うわー、これは私の最初の投稿stackoverflow、と私は非常に応答に満足している!私はあなたの1行のbasename-dirnameの答えを出しました。これは数字の仕事を提出する際に実行するスクリプトなので、しかし、私はたくさんの滑らかなbashの文字列トリックのためにこのスレッドを保存します! – user1059256

+0

+1、これは最も意味のある解決策です。 – harpo

1

私はグロブを使って短い方法があると思うが、私はパスをトリミングするために、具体的方法を知りませんが、あなたは確かにbash's regular expression matchingでそれを行うことができます

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

DIRNAME=/a/b/c/d/e 
if [[ "$DIRNAME" =~ ([^/]+/+[^/]+)/*$ ]]; then 
    echo "Last two: ${BASH_REMATCH[1]}" 
else 
    echo "No match" 
fi 

注:パス内に許可されているが一般的でないものを処理するために、ここでパターンを少し複雑にしました。後続のスラッシュをトリムし、複数の(冗長な)スラッシュを許容します最後の2つのnamの間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

不要なプロセスを作成しないように、できるだけ多くの組み込み関数を使用することをお勧めします。あなたのスクリプトは、Cygwinや他のOSで実行される可能性があるため、プロセスの作成には非常にコストがかかります。

私はあなたがちょうど2つのdirsを抽出したい場合、それはそう長くはないと思う。

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

これはまた別のコマンドを実行に関わる特殊な文字の問題を回避することができます。

+1

+1ベストソリューションIMHO。 – helpermethod

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