Come concatenare due stringhe per costruire un percorso completo


93

Sto cercando di scrivere uno script bash. In questo script voglio che l'utente inserisca un percorso di una directory. Quindi voglio aggiungere alcune stringhe alla fine di questa stringa e creare un percorso per alcune sottodirectory. Ad esempio, supponiamo che l'utente inserisca una stringa come questa:

/home/user1/MyFolder

Ora voglio creare 2 sottodirectory in questa directory e copiare alcuni file lì.

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

Come posso fare questo?


1
Cosa hai provato fino ad ora? Inoltre, fa parte della tua domanda sull'ottenere input dall'utente e l'altra parte sulla creazione del percorso? O solo il percorso?
Levon

Risposte:


135

Lo standard POSIX impone che più /siano trattati come un singolo /in un nome file. Quindi //dir///subdir////fileè lo stesso di /dir/subdir/file.

In quanto tale, concatenare due stringhe per costruire un percorso completo è semplice come:

full_path="$part1/$part2"

11
Tranne se $ part1 può essere una stringa vuota.
Tuure Laurinolli

1
@TuureLaurinolli Non capisco da dove vieni. La suddetta concatenazione risulterebbe comunque in un percorso valido. Il percorso potrebbe non esistere, ma sarebbe comunque valido. per esempio. "" + "/" + "Documents""/Documents".
Dune

17
Se le parti stesse sono percorsi relativi e part1 può essere vuota, il risultato potrebbe passare da percorso relativo a percorso assoluto.
Tuure Laurinolli

2
@TuureLaurinolli Quindi potresti semplicemente aggiungere ./in primo piano. Ma forse l'utente vuole concatenare percorsi assoluti. Altrimenti potrebbero semplicemente aggiungere ./in primo piano per forzare il percorso ad essere relativo. Nota anche che "$path1/./$path2"è lo stesso di "$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

E se vuoi usare readline in modo da ottenere il completamento e tutto il resto, aggiungi un -ealla chiamata a read:

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

1
Sfortunatamente, questo non funziona quando BASEPATH è vuoto. Quello di cui ho bisogno è qualcosa del genere che aggiunga solo un / quando non finisce già di una barra E non è vuoto. Pertanto, quando termina con un carattere di nome file legale.
Carlo Wood

17

Concatenare semplicemente la parte del tuo percorso non realizzerà ciò che desideri?

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

È quindi possibile creare le cartelle / directory secondo necessità.

Una convenzione è di terminare i percorsi di directory con /(ad esempio /home/) perché i percorsi che iniziano con / potrebbero essere confusi con la directory root. Se una doppia barra ( //) viene utilizzata in un percorso, è comunque corretta. Ma, se nessuna barra viene utilizzata su nessuna delle due variabili, non sarebbe corretto (ad esempio /home/user1/MyFoldersubFold1).


3
perché ricevo questo messaggio: Myscript.sh: riga 4: / home / utente1 / MyFolder / subFold1: è una directory
Hakim

2
Ti manca un / dal percorso. L'obiettivo è in linea, /home/user1/MyFolder/subFold1 quindi avresti bisogno di in linea new_path=$base/$subdir. Ma allora cosa fare se il percorso fornito include una "/" finale?
Thrasi

1
@Thrasi aggiungi semplicemente il finale "/" alla variabile subdir oppure newpath=$base/$subdir/puoi giocarci direttamente sulla riga di comando
user12345

3
@ user12345, Sì ... lascia ancora la soluzione sopra errata.
Thrasi

5

Il seguente script catena diversi percorsi (relativi / assoluti) (BASEPATH) con un percorso relativo (SUBDIR):

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

Il cui output è:

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

È shopt -s extglobnecessario solo per consentire a BASEPATH di terminare su più barre (che probabilmente non ha senso). Senza il globing esteso puoi semplicemente usare:

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

il che risulterebbe meno pulito ma ancora funzionante:

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

Stavo lavorando con il mio script di shell che ha bisogno di fare un po 'di cose che uniscono il percorso come fai tu.

Il fatto è che entrambi i percorsi piacciono

/data/foo/bar

/data/foo/bar/ 

sono validi.

Se voglio aggiungere un file a questo percorso come

/data/foo/bar/myfile

non c'era alcun metodo nativo (come os.path.join () in python) nella shell per gestire tale situazione.

Ma ho trovato un trucco

Ad esempio, il percorso di base è stato memorizzato in una variabile di shell

BASE=~/mydir

e l'ultimo nome di file a cui vuoi unirti era

FILE=myfile

Quindi puoi assegnare il tuo nuovo percorso in questo modo

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

e poi otterrai

$ echo $NEW_PATH

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

il motivo è abbastanza semplice, il comando "realpath" taglierà sempre la barra finale per te se necessario


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

Questo dovrebbe funzionare per la directory vuota (potrebbe essere necessario controllare se la seconda stringa inizia con /quale dovrebbe essere trattata come un percorso assoluto?):

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

Produzione:

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

Riferimento: espansione dei parametri della shell

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.