2011-12-19 24 views
5

Tôi muốn chia dòng nàyExtracting tên thư mục từ một đường dẫn tuyệt đối sử dụng sed hay awk

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

để

/home/edwprod/abortive_visit/bin 

sử dụng sed hoặc awk kịch bản? Bạn có thể giúp về điều này?

+0

Ngữ cảnh là gì? Có phải là trong một tập tin? Bạn có nhiều hơn một lần xuất hiện không? Bạn có ...? – fge

+1

sed và awk là overkill cho điều này, vỏ có tiện ích này trực tiếp. – Mat

+1

nếu bạn đang sử dụng bash: tại sao không sử dụng lệnh 'dirname'? – codeling

Trả lời

5

Có thể là lệnh dirname là những gì bạn đang tìm kiếm?

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

Hoặc nếu bạn muốn sed, vì vậy nhìn thấy giải pháp của tôi:

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

'sed' dựa trên giải pháp có một vấn đề với đường dẫn chỉ chứa tên cơ sở. 'dirname' trả về' .' trong trường hợp đó. –

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

Trong tất cả các lựa chọn thay thế để 'dirname' có một vấn đề với đường dẫn chỉ chứa tên cơ sở. 'dirname' cho' .' trong trường hợp đó. 'grep' trả về một chuỗi rỗng và một số khác hoạt động như' basename' –

1

awk + cho:

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

Đối với hầu hết các nền tảng và vỏ Unix/Linux bây giờ đã có dirname:

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

Sử dụng các dirname là cách đơn giản nhất , nhưng nó không được khuyến khích cho kịch bản nền tảng chéo ví dụ trong cuối cùng phiên bản của tài liệu autoconfhttp://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Limitations-of-Usual-Tools.html#Limitations-of-Usual-Tools.

Vì vậy, phiên bản đầy đủ tính năng của tôi về sed thay thế dựa trên cho 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#' - 

Ví dụ:

Nó hoạt động như dirname:

  • Đối với con đường như /aa/bb/cc nó sẽ in /aa/bb
  • Đối với đường dẫn như /aa/bb, đường dẫn sẽ in /aa
  • Đối với đường dẫn như /aa/bb/, cũng sẽ in /aa.
  • Đối với con đường như /aa/ nó sẽ in /aa
  • Đối với con đường như / nó sẽ in /
  • Đối với con đường như aa nó sẽ in .
  • Đối với con đường như aa/ nó sẽ in .

Đó là:

  • Nó hoạt động đúng với trailing /
  • Nó hoạt động đúng với đường dẫn chỉ chứa tên cơ sở như aaaa/
  • Nó hoạt động đúng với đường dẫn bắt đầu với / và đường dẫn / riêng của mình.
  • Nó hoạt động đúng với bất kỳ $str nếu nó chứa \n ở cuối hay không, thậm chí với nhiều \n
  • Nó sử dụng nền tảng chéo sed lệnh
  • Nó thay đổi tất cả các kết hợp của / (/////) để /
  • Nó không thể hoạt động chính xác với các đường dẫn chứa các dòng mới và ký tự không hợp lệ cho ngôn ngữ hiện tại.

Note Alternative cho basename có thể hữu ích:

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

Mã này với awk sẽ làm việc một cách hoàn hảo như giống như dirname, tôi đoán.

Rất đơn giản và có chi phí rất thấp để hoạt động. Chúc may mắn.

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

quả

/app/java/jdk1.7.0_71/bin

thử nghiệm

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

More

Nếu bạn không có sẵn awk delimiter như vậy, hãy thử theo cách này.

$ echo $foo | awk '{ 
dirname = gensub("/?[^/]*/?$", "", "", $0); 
print (dirname == "" ? (substr($0, 1, 1) == "/" ? "/" : ".") : dirname); 
}' 
Các vấn đề liên quan