2011-12-19 8 views
5

Chcę podzielić tę linięWyodrębnianie nazwy katalogu z bezwzględną ścieżkę przy użyciu sed lub awk

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

do

/home/edwprod/abortive_visit/bin 

wykorzystaniem sed lub awk skrypty? Czy możesz w tym pomóc?

+0

Jaki jest kontekst? Czy to w pliku? Czy masz więcej niż jedno zdarzenie? Czy ty... ? – fge

+1

sed i awk są przesadzone, powłoki mają narzędzia do tego bezpośrednio. – Mat

+1

jeśli używasz bash: dlaczego nie użyć polecenia 'dirname'? – codeling

Odpowiedz

5

Może być polecenie nazwa dan jest tym, czego szukasz?

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

Albo jeśli chcesz sed, więc zobacz moje rozwiązanie:

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

'Rozwiązanie oparte na' sed' ma problem ze ścieżką zawierającą tylko nazwę bazową. 'dirname' zwraca' .' w tym przypadku. –

11

dirname

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

We wszystkich tych alternatywach do 'dirname' występuje problem ze ścieżkami zawierającymi tylko basename. 'dirname' daje' .' w tym przypadku. 'grep' zwraca pusty łańcuch, a inne działają jako' basename' –

1

awk + dla:

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

Dla większości platform i muszli Unix/Linux obecnie dostępnych dirname:

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

Korzystanie z dirname jest najprostszy sposób , ale nie jest zalecane dla skryptów międzyplatformowych, na przykład w ostatnim wersja autoconf dokumentacja http://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Limitations-of-Usual-Tools.html#Limitations-of-Usual-Tools.

Więc mój pełni funkcjonalnym wersja sed opartym alternatywa dla 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#' - 

Przykłady:

To działa jak dirname:

  • dla ścieżki jak /aa/bb/cc zostanie wydrukowana /aa/bb
  • Dla ścieżki podobnej do /aa/bb zostanie wydrukowane: /aa
  • Dla ścieżki takiej jak /aa/bb/ będzie również drukować /aa.
  • Na ścieżce jak /aa/ zostanie wydrukowana /aa
  • Na ścieżce jak / zostanie wydrukowana /
  • dla ścieżki jak aa będzie drukować .
  • Na ścieżce jak aa/ zostanie wydrukowana .

To jest:

  • Działa poprawne ze spływu /
  • Działa poprawne ze ścieżki, która zawiera tylko nazwę bazową jak i aa/aa
  • Działa poprawne ze ścieżek zaczynających się / i ścieżki / samego.
  • Działa on poprawny z dowolnym $str jeśli zawiera \n na końcu, czy nie, nawet z wieloma \n
  • Wykorzystuje sed polecenie wieloplatformowym
  • Zmienia wszystkie kombinacje / (/////) do /
  • Nie działa poprawnie w przypadku ścieżek zawierających znaki nowej linii i znaki nieprawidłowe dla bieżących ustawień narodowych.

Uwaga Alternatywa dla basename mogą być użyteczne:

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

Ten kod z awk będzie działać idealnie tak samo jak dirname, tak myślę.

Jest to bardzo proste i ma bardzo niski koszt pracy. Powodzenia.

Kod

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

Wynik

/app/java/jdk1.7.0_71/bin

test

  • 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/ ->.

Więcej

Jeśli nie jesteś dostępny takich awk separator, spróbuj go w ten sposób.

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