2012-06-11 10 views
31

Sto tentando di rimuovere parte del percorso in una stringa. Ho il percorso:Unix rimuove parte del 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 loro, 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 essere la seconda parte della stringa e sto chiaramente facendo qualcosa di sbagliato ... forse c'è un più facile modo?

risposta

28

È inoltre possibile utilizzare shell POSIX espansione variabile per fare questo.

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

La parte #.. spoglia una stringa che porta corrispondente quando si espande la variabile; questo è particolarmente utile se le stringhe sono già in variabili di shell, come se si stesse utilizzando un ciclo for. Puoi anche rimuovere le stringhe corrispondenti (ad es. Un'estensione) dalla fine di una variabile, usando %.... Vedi la pagina man bash per i dettagli cruenti.

+0

Grazie ... Sì, sto usando le variabili di shell per eseguire questo. Entrambe le parti sono variabili, quella che devo cancellare e il percorso completo. – esausilva

+0

Eccellente! Ma come posso usarlo quando la corda sta arrivando "da una pipa"? – gromit190

+0

@Birger se la stringa proviene da una pipe, è necessario inserirla in una variabile per utilizzare l'espansione della variabile di shell. O semplicemente usi 'sed' in quel caso. –

9

Un modo per fare questo con sed è

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

Grazie. Funziona bene – esausilva

+0

Impressionante: non avevo idea che il delimitatore sed potesse essere un ":" (due punti) anziché "/" (barra). Elegante e funziona perfettamente. – stachyra

+0

Puoi utilizzare quasi tutti i delimitatori con sed, non solo/e: finché sei coerente. –

18

Se non si desidera hardcode parte si sta rimuovendo:

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

Ho passato 2 ore a guardare come si fa. e tu eri l'unico a pubblicare un modo per visualizzare solo il nome di una directory senza hardcoding. Dovevo fare: 'find/path/to/file/drive/file/* _ TST -maxdepth 0 -type d' Ma volevo mostrare solo i nomi delle directory senza il percorso completo. e questo è stato. – Whitecat

+0

@Whitecat è quello che volevi, leggi "man find", in particolare "-printf". Puoi specificare '-printf "% h \ n"'. Ricorda solo che stamperà la directory per ogni file corrispondente, quindi dovresti filtrarla attraverso "uniq". –

3

Utilizzando ${path#/path/to/file/drive/} come suggerito da Otto male è certamente il/modo migliore tipico per fare questo, ma dal momento che ci sono molti sed suggerimenti vale la pena sottolineare che sed è eccessivo se si lavora con una stringa fissa. È anche possibile fare:

echo $PATH | cut -b 21- 

di scartare i primi 20 caratteri. Allo stesso modo, è possibile utilizzare ${PATH:20} in bash o $PATH[20,-1] in zsh.

+0

Grazie. Sto usando la risposta del malvagio Otto. La parte che voglio rimuovere è fissa, ma può cambiare se sposto il mio script in una casella/percorso diverso. Quindi, avere la parte che voglio rimuovere dal percorso in una variabile rende più facile il conteggio .... ma le informazioni che hai fornito sono buone da sapere :) – esausilva

2

Se si desidera rimuovere le prime parti N del percorso, si potrebbe ovviamente usare N chiamate a basename, come in glenn's answer, ma è probabilmente più facile da usare globbing:

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

Nello specifico, ${path#*/*/*/*/*/} significa "restituisce $path meno il prefisso più breve che contiene 5 barre".

32

Se si desidera rimuovere un determinato NUMERO di componenti del percorso, è necessario utilizzare 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 le ultime due componenti (rev inverte la stringa) :

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

Per mantenere gli ultimi tre componenti Ent:

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

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

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

O dopo un particolare componente:

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

E 'ancora più facile se non vuoi mantenere il componente che stai specificando:

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

E se si vuole essere coerenti si può abbinare la barra finale troppo:

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

Naturalmente, se si sta corrispondenza diversi tagli, si dovrebbe passare il sed delimitatore:

$ 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.

+0

Sorprendente risposta, in particolare il doppio trucco 'rev'. Will upvote quando il mio voto cap esaurirà domani. –

+1

eccellente, risposta informativa nello spirito originale Unix, e molto meglio di {chopsquiggleSquiggle}: solo: shellversionyoumaynonhave. –

Problemi correlati