So verketten Sie zwei Zeichenfolgen, um einen vollständigen Pfad zu erstellen

93

Ich versuche ein Bash-Skript zu schreiben. In diesem Skript soll der Benutzer einen Pfad eines Verzeichnisses eingeben. Dann möchte ich einige Zeichenfolgen am Ende dieser Zeichenfolge anhängen und einen Pfad zu einigen Unterverzeichnissen erstellen. Angenommen, der Benutzer gibt eine Zeichenfolge wie folgt ein:

/home/user1/MyFolder

Jetzt möchte ich 2 Unterverzeichnisse in diesem Verzeichnis erstellen und einige Dateien dort kopieren.

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

Wie kann ich das machen?

Hakim
quelle
1
Was hast du bisher versucht? Ist ein Teil Ihrer Frage, ob Sie Eingaben vom Benutzer erhalten, und der andere Teil, wie Sie den Pfad erstellen? Oder nur der Weg?
Levon

Antworten:

133

Der POSIX-Standard schreibt vor, dass mehrere in einem Dateinamen /als eine einzige behandelt werden /. Also //dir///subdir////fileist das gleiche wie /dir/subdir/file.

Das Verketten von zwei Zeichenfolgen zum Erstellen eines vollständigen Pfads ist daher wie folgt:

full_path="$part1/$part2"
Dünen
quelle
11
Außer wenn $ part1 eine leere Zeichenfolge sein kann.
Tuure Laurinolli
1
@ TuureLaurinolli Ich verstehe nicht, woher du kommst. Die obige Verkettung würde immer noch zu einem gültigen Pfad führen. Der Pfad ist möglicherweise nicht vorhanden, aber weiterhin gültig. z.B. "" + "/" + "Documents"gibt "/Documents".
Dünen
17
Wenn die Teile selbst relative Pfade sind und Teil1 leer sein kann, kann sich das Ergebnis vom relativen zum absoluten Pfad ändern.
Tuure Laurinolli
2
@ TuureLaurinolli Dann könnten Sie einfach ./nach vorne hinzufügen . Aber vielleicht möchte der Benutzer absolute Pfade zusammenfassen. Andernfalls könnten sie einfach ./nach vorne addieren, um zu erzwingen, dass der Pfad relativ ist. Beachten Sie auch, dass dies "$path1/./$path2"dasselbe ist wie "$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

Und wenn Sie readline verwenden möchten, um die Fertigstellung und all das zu erhalten, fügen Sie -edem Aufruf ein hinzu read:

read -e -p "Enter a directory: " BASEPATH
Sean Bright
quelle
1
Leider funktioniert dies nicht, wenn BASEPATH leer ist. Was ich brauche, ist so etwas, das nur dann ein / hinzufügt, wenn es noch nicht mit einem Schrägstrich endet UND nicht leer ist. Wenn es also mit einem legalen Dateinamen endet.
Carlo Wood
16

Wird die Verkettung des Teils Ihres Pfades nicht einfach das erreichen, was Sie wollen?

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

Sie können dann die Ordner / Verzeichnisse nach Bedarf erstellen.

Eine Konvention besteht darin, Verzeichnispfade mit /(z. B. /home/) zu beenden, da Pfade, die mit einem / beginnen, mit dem Stammverzeichnis verwechselt werden könnten. Wenn //in einem Pfad ein doppelter Schrägstrich ( ) verwendet wird, ist dieser ebenfalls weiterhin korrekt. Wenn jedoch für keine der Variablen ein Schrägstrich verwendet wird, ist dies falsch (z /home/user1/MyFoldersubFold1. B. ).

Levon
quelle
3
Warum bekomme ich diese Nachricht: Myscript.sh: Zeile 4: / home / user1 / MyFolder / subFold1: Ist ein Verzeichnis
Hakim
2
Ihnen fehlt ein / aus dem Pfad. Das Ziel ist Inline /home/user1/MyFolder/subFold1 , Sie benötigen also Inline new_path=$base/$subdir. Aber was machen Sie dann, wenn der angegebene Pfad ein abschließendes '/' enthält?
Thrasi
1
@ Thrasi fügen Sie einfach das nachfolgende '/' entweder zur Subdir-Variablen hinzu oder newpath=$base/$subdir/Sie können damit direkt in der Befehlszeile spielen
user12345
3
@ user12345, Ja ... lässt die obige Lösung immer noch falsch.
Thrasi
5

Das folgende Skript verkettet mehrere (relative / absolute) Pfade (BASEPATH) mit einem relativen Pfad (SUBDIR):

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

Die Ausgabe davon ist:

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

Das shopt -s extglobist nur notwendig , BASEPATH zu ermöglichen , sich auf mehrere Schrägstriche zu beenden (was wahrscheinlich ist Unsinn). Ohne erweitertes Globing können Sie einfach Folgendes verwenden:

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

was dazu führen würde, dass weniger ordentlich, aber immer noch funktioniert:

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
Carlo Wood
quelle
1

Ich habe mit meinem Shell-Skript herumgearbeitet, das einige Pfadverbindungsaufgaben wie Sie ausführen muss.

Die Sache ist, beide Wege mögen

/data/foo/bar

/data/foo/bar/ 

sind gültig.

Wenn ich eine Datei an diesen Pfad anhängen möchte wie

/data/foo/bar/myfile

Es gab keine native Methode (wie os.path.join () in Python) in der Shell, um mit einer solchen Situation umzugehen.

Aber ich habe einen Trick gefunden

Beispielsweise wurde der Basispfad in einer Shell-Variablen gespeichert

BASE=~/mydir

und der letzte Dateiname, dem Sie beitreten möchten, war

FILE=myfile

Dann können Sie Ihren neuen Pfad wie folgt zuweisen

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

und dann wirst du bekommen

$ echo $NEW_PATH

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

Der Grund ist recht einfach. Der Befehl "realpath" schneidet bei Bedarf immer den abschließenden Schrägstrich für Sie ab

余晓晨
quelle
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 "$@"
Ormaaj
quelle
0

Dies sollte für ein leeres Verzeichnis funktionieren (Möglicherweise müssen Sie überprüfen, ob die zweite Zeichenfolge beginnt, mit /der als absoluter Pfad behandelt werden soll?):

#!/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

Ausgabe:

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

Referenz: Erweiterung der Shell-Parameter

tsl0922
quelle