Rimuovi parte del percorso su Unix

Sto cercando di rimuovere parte del percorso in una stringa. Ho il percorso:

/path/to/file/drive/file/path/ 

Voglio rimuovere la prima parte /path/to/file/drive e produrre l’output:

 file/path/ 

Nota: ho diversi percorsi in un ciclo while, con lo stesso /path/to/file/drive in tutti, ma sto solo cercando il “come” per rimuovere la stringa desiderata.

Ho trovato alcuni esempi, ma non riesco a farli funzionare:

 echo /path/to/file/drive/file/path/ | sed 's:/path/to/file/drive:\2:' echo /path/to/file/drive/file/path/ | sed 's:/path/to/file/drive:2' 

\2 è la seconda parte della stringa e sto chiaramente facendo qualcosa di sbagliato … forse c’è un modo più semplice?

Puoi anche usare l’espansione delle variabili della shell POSIX per fare ciò.

 path=/path/to/file/drive/file/path/ echo ${path#/path/to/file/drive/} 

La parte #.. rimuove una stringa di corrispondenza principale quando la variabile viene espansa; questo è particolarmente utile se le stringhe sono già in variabili di shell, come se si stesse usando un ciclo for . Puoi anche eliminare le stringhe corrispondenti (ad esempio un’estensione) dalla fine di una variabile, usando %... Vedi la pagina man bash per i dettagli cruenti.

Se si desidera rimuovere un determinato NUMERO di componenti del percorso, è necessario utilizzare il cut con -d'/' . Ad esempio, se path=/home/dude/some/deepish/dir :

Per rimuovere i primi due componenti:

 # (Add 2 to the number of components to remove to get the value to pass to -f) $ echo $path | cut -d'/' -f4- some/deepish/dir 

Per mantenere i primi due componenti:

 $ echo $path | cut -d'/' -f-3 /home/dude 

Per rimuovere gli ultimi due componenti ( rev inverte la stringa):

 $ echo $path | rev | cut -d'/' -f4- | rev /home/dude/some 

Per mantenere gli ultimi tre componenti:

 $ echo $path | rev | cut -d'/' -f-3 | rev some/deepish/dir 

Oppure, se si desidera rimuovere tutto prima di un particolare componente, sed funzionerebbe:

 $ echo $path | sed 's/.*\(some\)/\1/g' some/deepish/dir 

O dopo un particolare componente:

 $ echo $path | sed 's/\(dude\).*/\1/g' /home/dude 

È ancora più semplice se non vuoi mantenere il componente che stai specificando:

 $ echo $path | sed 's/some.*//g' /home/dude/ 

E se vuoi essere coerente puoi uguagliare anche la barra finale:

 $ echo $path | sed 's/\/some.*//g' /home/dude 

Ovviamente, se combini diverse barre, devi cambiare il delimitatore sed :

 $ echo $path | sed 's!/some.*!!g' /home/dude 

Nota che questi esempi usano tutti i percorsi assoluti, dovrai giocare per farli funzionare con percorsi relativi.

Se non si desidera eseguire l’hardcode della parte che si sta rimuovendo:

 $ s='/path/to/file/drive/file/path/' $ echo ${s#$(dirname "$(dirname "$s")")/} file/path/ 

Un modo per farlo con sed è

 echo /path/to/file/drive/file/path/ | sed 's:^/path/to/file/drive/::' 

Usare ${path#/path/to/file/drive/} come suggerito dal male otto è certamente il modo tipico / migliore per farlo, ma dato che ci sono molti suggerimenti sed, vale la pena sottolineare che sed è eccessivo se si è lavorando con una stringa fissa. Puoi anche fare:

 echo $PATH | cut -b 21- 

Per scartare i primi 20 caratteri. Allo stesso modo, puoi usare ${PATH:20} in bash o $PATH[20,-1] in zsh.

Se vuoi rimuovere le prime N parti del percorso , potresti ovviamente usare N chiamate a basename , come nella risposta di Glenn , ma probabilmente è più facile usare il globbing:

 path=/path/to/file/drive/file/path/ echo "${path#*/*/*/*/*/}" # file/path/ 

In particolare, ${path#*/*/*/*/*/} significa “ritorno $path meno il prefisso più breve che contiene 5 barre” .

Pure bash, senza hard coding la risposta

 basenames() { local d="${2}" for ((x=0; x<"${1}"; x++)); do d="${d%/*}" done echo "${2#"${d}"/}" } 
  • Argomento 1 - Quanti livelli vuoi mantenere (2 nella domanda originale)
  • Argomento 2 - Il percorso completo