2011-12-19 11 views
5

Voglio dividere questa lineaEstrazione nome di directory da un percorso assoluto utilizzando sed o awk

/home/edwprod/abortive_visit/bin/abortive_proc_call.ksh 

a

/home/edwprod/abortive_visit/bin 

utilizzando sed o awk script? Potresti aiutare su questo?

+0

Qual è il contesto? È in un file? Hai più di un evento? Fai... ? – fge

+1

sed e awk sono overkill per questo, le shell hanno utility per questo direttamente. – Mat

+1

se stai usando bash: perché non usare il comando 'dirname'? – codeling

risposta

5

Può essere il comando dirname è quello che stai cercando?

dirname /home/edwprod/abortive_visit/bin/abortive_proc_call.ksh 

O se volete sed, in modo da vedere la mia soluzione:

echo /home/edwprod/abortive_visit/bin/abortive_proc_call.ksh | sed 's/\(.*\)\/.*/\1/' 
+1

La soluzione basata su 'sed' ha un problema con il percorso contenente solo il nome base. 'dirname' restituisce' .' in questo caso. –

11

nomedir

kent$ dirname "/home/edwprod/abortive_visit/bin/abortive_proc_call.ksh" 
/home/edwprod/abortive_visit/bin 

sed

kent$ echo "/home/edwprod/abortive_visit/bin/abortive_proc_call.ksh"|sed 's#/[^/]*$##' 
/home/edwprod/abortive_visit/bin 

grep

kent$ echo "/home/edwprod/abortive_visit/bin/abortive_proc_call.ksh"|grep -oP '^/.*(?=/)' 
/home/edwprod/abortive_visit/bin 

awk

kent$ echo "/home/edwprod/abortive_visit/bin/abortive_proc_call.ksh"|awk -F'/[^/]*$' '{print $1}' 
/home/edwprod/abortive_visit/bin 
+1

In tutte queste alternative a 'dirname' c'è un problema con i percorsi che contengono solo basename. 'dirname' dà' .' in quel caso. La versione 'grep' restituisce una stringa vuota e altri funzionano come' basename' –

1

awk + per:

echo "/home/edwprod/abortive_visit/bin/abortive_proc_call.ksh" | awk 'BEGIN{res=""; FS="/";}{ for(i=2;i<=NF-1;i++) res=(res"/"$i);} END{print res}' 
0

Per la maggior parte delle piattaforme e gusci di Unix/Linux ora disponibili dirname:

dirname /home/edwprod/abortive_visit/bin/abortive_proc_call.ksh 

Usando della dirname è il modo più semplice , ma non è raccomandato per lo scripting multipiattaforma, ad esempio nell'ultimo versione della documentazione autoconfhttp://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Limitations-of-Usual-Tools.html#Limitations-of-Usual-Tools.

Quindi la mia versione completa funzionalità di sed basata su alternative per dirname:

str="/home/edwprod/abortive_visit/bin/abortive_proc_call.ksh" 
echo "$str" | sed -n -e '1p' | sed -e 's#//*#/#g' -e 's#\(.\)/$#\1#' -e 's#^[^/]*$#.#' -e 's#\(.\)/[^/]*$#\1#' - 

Esempi:

Funziona come dirname:

  • per il percorso come /aa/bb/cc verrà stampata /aa/bb
  • Per percorso come /aa/bb verrà stampata /aa
  • per il percorso come /aa/bb/ verrà stampata /aa troppo.
  • per il percorso come /aa/ verrà stampata /aa
  • per il percorso come / verrà stampata /
  • per il percorso come aa verrà stampata .
  • per il percorso come aa/ verrà stampata .

Ovvero:

  • Funziona corretta con il trascinamento /
  • Funziona corretta con percorsi che contiene solo nome di base come aa e aa/
  • Funziona corretta con percorsi che iniziano con / e il percorso / stessa.
  • Funziona corrette in qualsiasi $str se contiene \n alla fine o no, anche con molti \n
  • Esso utilizza comando piattaforma trasversale sed
  • Esso cambia tutte le combinazioni di / (/////) per /
  • Non può funzionare correttamente con percorsi contenenti caratteri di nuova riga e caratteri non validi per le impostazioni internazionali correnti.

Nota alternativa per basename può essere utile:

echo "$str" | awk -F"/" '{print $NF}' - 
0

Questo codice con awk funziona perfettamente come stessi dirname, immagino.

È così semplice e ha un costo molto basso per funzionare. In bocca al lupo.

Codice

$ foo=/app/java/jdk1.7.0_71/bin/java 
$ echo "$foo" | awk -F "/?[^/]*/?$" ' 
{ print ($1 == "" ? (substr($0, 1, 1) == "/" ? "/" : ".") : $1); }' 

Risultato

/app/java/jdk1.7.0_71/bin

prova

  • foo=/app/java/jdk1.7.0_71/bin/java ->/app/java/jdk1.7.0_71/bin
  • foo=/app/java/jdk1.7.0_71/bin/ ->/app/java/jdk1.7.0_71
  • foo=/app/java/jdk1.7.0_71/bin ->/app/java/jdk1.7.0_71
  • foo=/app/ ->/
  • foo=/app ->/
  • foo=fighters/ ->.

Più

Se non si è disponibili ad delimitatore awk, provare in questo modo.

$ echo $foo | awk '{ 
dirname = gensub("/?[^/]*/?$", "", "", $0); 
print (dirname == "" ? (substr($0, 1, 1) == "/" ? "/" : ".") : dirname); 
}' 
Problemi correlati