Pobierz ścieżkę do katalogu ze ścieżki pliku


400

W Bash, VAR="/home/me/mydir/file.c"jak mogę uzyskać "/home/me/mydir"?

Odpowiedzi:


647

dirnamei basenamesą to narzędzia, których szukasz do wyodrębnienia komponentów ścieżki:

$ VAR=/home/me/mydir/file.c

$ DIR=$(dirname "${VAR}")

$ echo "${DIR}"
/home/me/mydir

$ basename "${VAR}"
file.c

Nie są to wewnętrzne komendy Bash, ale są częścią standardu POSIX (patrz dirname, basename) i dlatego powinny być dostępne w zdecydowanej większości systemów, w których działa Bash.


4
Dlaczego stosowanie nawiasów wokół nazw zmiennych, a nie na przykład „$ VAR”?
user658182

1
stackoverflow.com/questions/8748831/... odpowiada na powyższe pytanie.
user658182

1
@ user658182 W tym konkretnym przykładzie dzieje się to z przyzwyczajenia, a nie z konieczności.
Opuszczony

95
$ export VAR=/home/me/mydir/file.c
$ export DIR=${VAR%/*}
$ echo "${DIR}"
/home/me/mydir

$ echo "${VAR##*/}"
file.c

Aby uniknąć zależności z basenameidirname


3
Ponieważ oba są częścią POSIX, zależność nie powinna stanowić problemu.
orkoden

1
orkoden, masz rację. Moja odpowiedź ma na celu wykazanie, że nie ma obowiązku wykonania dwóch dodatkowych procesów. bash jest samowystarczalny dla przypadku użycia.
Emmanuel Devaux,

2
Używam metody Emmanuela, ponieważ chcę przekazać nazwę pliku lub folderu, a następnie obliczyć ścieżkę folderu. Używanie tego wyrażenia regularnego robi dobrze, podczas gdy funkcja dirname zwróciła folder nadrzędny, gdy wprowadzam folder.
AnneTheAgile,

8
Jednak jeśli w $ VAR nie ma informacji o ścieżce, $ {VAR% / *} / test generuje nieoczekiwaną wartość równą $ VAR / test, podczas gdy $ (nazwa katalogu $ VAR) da bardziej przewidywalną i odpowiednią wartość ./test. Jest to wielka sprawa, ponieważ ta pierwsza spróbuje traktować nazwę pliku jako katalog, a druga będzie w porządku.
davemyron

19

W powiązanej notatce, jeśli masz tylko nazwę pliku lub ścieżkę względną, dirnamesamo w sobie nie pomoże. Dla mnie odpowiedź była ostateczna readlink.

fname='txtfile'    
echo $(dirname "$fname")                # output: .
echo $(readlink -f "$fname")            # output: /home/me/work/txtfile

Następnie możesz połączyć te dwa elementy, aby uzyskać tylko katalog.

echo $(dirname $(readlink -f "$fname")) # output: /home/me/work

1
jeśli nie istnieje więcej niż jeden komponent ścieżki, należy użyć readlink -m "$fname"do kanonicznej rekurencyjnej podanej nazwy
EDkan

7

Jeśli zależy ci na tym, aby pliki docelowe były linkami symbolicznymi, najpierw możesz to sprawdzić i uzyskać oryginalny plik. Poniższa klauzula if może ci pomóc.

if [ -h $file ]
then
 base=$(dirname $(readlink $file))
else
 base=$(dirname $file)
fi

5

Bawiłem się tym i wpadłem na alternatywę.

$ VAR=/home/me/mydir/file.c

$ DIR=`echo $VAR |xargs dirname`

$ echo $DIR
/home/me/mydir

Najbardziej podobało mi się to, że łatwo było rozszerzyć kopię zapasową drzewa:

$ DIR=`echo $VAR |xargs dirname |xargs dirname |xargs dirname`

$ echo $DIR
/home

1

Oto skrypt, którego użyłem do przycinania rekurencyjnego. Oczywiście zamień $ 1 na żądany katalog.

BASEDIR="$1"
IFS=$'\n'
cd $BASEDIR
 for f in $(find . -type f -name ' *')
 do 
    DIR=$(dirname "$f")
    DIR=${DIR:1}
    cd $BASEDIR$DIR
    rename 's/^ *//' *
 done

0

Najpierw zastąpiłem /pustą spacją ( ). Następnie usunąłem wszystkie znaki przed pustą spacją ( ). Na koniec usunąłem pierwszy znak, który jest pustą spacją ( ).

$ VAR="/home/me/mydir/file.c"

$ echo $VAR | tr '/' ' ' | sed 's/^.* / /' | cut -c2-
file.c

0
HERE=$(cd $(dirname $BASH_SOURCE) && pwd)

gdzie otrzymujesz pełną ścieżkę z new_path = $(dirname ${BASH_SOURCE[0]}). cd Zmieniasz bieżący katalog za pomocą new_path, a następnie biegniesz, pwdaby uzyskać pełną ścieżkę do bieżącego katalogu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.