Jak połączyć dwa ciągi, aby zbudować kompletną ścieżkę


95

Próbuję napisać skrypt basha. W tym skrypcie chcę, aby użytkownik wprowadził ścieżkę do katalogu. Następnie chcę dołączyć kilka ciągów na końcu tego ciągu i zbudować ścieżkę do niektórych podkatalogów. Na przykład załóżmy, że użytkownik wprowadza następujący ciąg:

/home/user1/MyFolder

Teraz chcę utworzyć 2 podkatalogi w tym katalogu i skopiować tam kilka plików.

/home/user1/MyFolder/subFold1
/home/user1/MyFolder/subFold2

Jak mogę to zrobić?


1
Czego spróbowałeś do tej pory? Czy część pytania dotyczy uzyskiwania informacji od użytkownika, a druga - budowania ścieżki? A może po prostu ścieżka?
— Levon

Odpowiedzi:


136

Standard POSIX wymaga, aby wiele było /traktowanych jako pojedyncze /w nazwie pliku. Zatem //dir///subdir////filejest tym samym, co /dir/subdir/file.

W związku z tym połączenie dwóch ciągów w celu zbudowania pełnej ścieżki jest proste, jak:

full_path="$part1/$part2"

11
Z wyjątkiem sytuacji, gdy $ part1 może być pustym łańcuchem.
— Tuure Laurinolli

1
@TuureLaurinolli Nie rozumiem, skąd pochodzisz. Powyższa konkatenacja nadal skutkowałaby prawidłową ścieżką. Ścieżka może nie istnieć, ale nadal byłaby ważna. na przykład. "" + "/" + "Documents"daje "/Documents".
— Dunes

17
Jeśli same części są ścieżkami względnymi, a część 1 może być pusta, wynik może zmienić się ze ścieżki względnej na ścieżkę bezwzględną.
— Tuure Laurinolli,

2
@TuureLaurinolli Następnie możesz po prostu dodać ./z przodu. Ale może użytkownik chce połączyć ścieżki bezwzględne. W przeciwnym razie mogliby po prostu dodać ./do przodu, aby wymusić względną ścieżkę. Zauważ też, że "$path1/./$path2"to to samo, co "$path1/$path2".
— yyny,

41
#!/bin/bash

read -p "Enter a directory: " BASEPATH

SUBFOLD1=${BASEPATH%%/}/subFold1
SUBFOLD2=${BASEPATH%%/}/subFold2

echo "I will create $SUBFOLD1 and $SUBFOLD2"

# mkdir -p $SUBFOLD1
# mkdir -p $SUBFOLD2

A jeśli chcesz użyć readline, aby ukończyć i tak dalej, dodaj -edo wywołania read:

read -e -p "Enter a directory: " BASEPATH

1
Niestety, to nie działa, gdy BASEPATH jest pusty. To, czego potrzebuję, to coś takiego, które dodaje / tylko wtedy, gdy nie kończy się już ukośnikiem ORAZ nie jest puste. Tak więc, kiedy kończy się na legalnym znaku nazwy pliku.
— Carlo Wood

17

Czy po prostu połączenie części ścieżki nie przyniesie tego, czego chcesz?

$ base="/home/user1/MyFolder/"
$ subdir="subFold1"
$ new_path=$base$subdir
$ echo $new_path
/home/user1/MyFolder/subFold1

Następnie możesz utworzyć foldery / katalogi według potrzeb.

Jedną z konwencji jest kończenie ścieżek katalogów /(np. /home/), Ponieważ ścieżki zaczynające się od / mogą zostać pomylone z katalogiem głównym. Jeśli //w ścieżce użyto podwójnego ukośnika ( ), to również jest poprawne. Ale jeśli na żadnej ze zmiennych nie zostanie użyty ukośnik, będzie on niepoprawny (np /home/user1/MyFoldersubFold1.).


3
dlaczego otrzymuję tę wiadomość: Myscript.sh: wiersz 4: / home / user1 / MyFolder / subFold1: Is a directory
— Hakim

2
Brakuje / ze ścieżki. Celem jest inline, /home/user1/MyFolder/subFold1 więc potrzebujesz inline new_path=$base/$subdir. Ale co zrobić, jeśli podana ścieżka zawiera na końcu „/”?
— Thrasi

1
@Thrasi po prostu dodaj końcowe '/' albo do zmiennej subdir, albo newpath=$base/$subdir/możesz grać z tym bezpośrednio w linii poleceń
— user12345

3
@ user12345, Tak ... nadal pozostawia powyższe rozwiązanie niepoprawne.
— Thrasi

5

Poniższy skrypt łączy kilka (względnych / bezwzględnych) ścieżek (BASEPATH) ze ścieżką względną (SUBDIR):

shopt -s extglob
SUBDIR="subdir"
for BASEPATH in '' / base base/ base// /base /base/ /base//; do
  echo "BASEPATH = \"$BASEPATH\" --> ${BASEPATH%%+(/)}${BASEPATH:+/}$SUBDIR"
done

Wynik którego jest:

BASEPATH = "" --> subdir
BASEPATH = "/" --> /subdir
BASEPATH = "base" --> base/subdir
BASEPATH = "base/" --> base/subdir
BASEPATH = "base//" --> base/subdir
BASEPATH = "/base" --> /base/subdir
BASEPATH = "/base/" --> /base/subdir
BASEPATH = "/base//" --> /base/subdir

Jest shopt -s extglobto konieczne tylko, aby pozwolić BASEPATH kończyć się wieloma ukośnikami (co jest prawdopodobnie nonsensem). Bez rozszerzonego globowania możesz po prostu użyć:

echo ${BASEPATH%%/}${BASEPATH:+/}$SUBDIR

co spowodowałoby mniej schludne, ale nadal działające:

BASEPATH = "" --> subdir
BASEPATH = "/" --> /subdir
BASEPATH = "base" --> base/subdir
BASEPATH = "base/" --> base/subdir
BASEPATH = "base//" --> base//subdir
BASEPATH = "/base" --> /base/subdir
BASEPATH = "/base/" --> /base/subdir
BASEPATH = "/base//" --> /base//subdir

1

Pracowałem z moim skryptem powłoki, który musi łączyć ścieżki, tak jak ty.

Chodzi o to, że obie ścieżki

/data/foo/bar

/data/foo/bar/ 

są ważne.

Jeśli chcę dołączyć plik do tej ścieżki, na przykład

/data/foo/bar/myfile

nie było natywnej metody (jak os.path.join () w pythonie) w powłoce do obsługi takiej sytuacji.

Ale znalazłem sztuczkę

Na przykład ścieżka podstawowa była przechowywana w zmiennej powłoki

BASE=~/mydir

a ostatnia nazwa pliku, do którego chcesz dołączyć, to

FILE=myfile

Następnie możesz przypisać nową ścieżkę w ten sposób

NEW_PATH=$(realpath ${BASE})/FILE

a wtedy dostaniesz

$ echo $NEW_PATH

/path/to/your/home/mydir/myfile

powód jest bardzo prosty, polecenie „realpath” zawsze usuwałoby kończący ukośnik, jeśli to konieczne


0
#!/usr/bin/env bash

mvFiles() {
    local -a files=( file1 file2 ... ) \
             subDirs=( subDir1 subDir2 ) \
             subDirs=( "${subDirs[@]/#/$baseDir/}" )

    mkdir -p "${subDirs[@]}" || return 1

    local x
    for x in "${subDirs[@]}"; do
        cp "${files[@]}" "$x"
    done
}



main() {
    local baseDir
    [[ -t 1 ]] && echo 'Enter a path:'
    read -re baseDir
    mvFiles "$baseDir"
}

main "$@"

0

Powinno to zadziałać dla pustego katalogu (może być konieczne sprawdzenie, czy zaczyna się drugi ciąg, od /którego należy traktować jako ścieżkę bezwzględną?):

#!/bin/bash

join_path() {
    echo "${1:+$1/}$2" | sed 's#//#/#g'
}

join_path "" a.bin
join_path "/data" a.bin
join_path "/data/" a.bin

Wynik:

a.bin
/data/a.bin
/data/a.bin

Odniesienie: Rozszerzenie parametrów powłoki

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.