linux
  • bash
  • recursion
  • sed
  • grep
  • 2013-04-10 11 views 28 likes 
    28

    Tôi nhận được mộtTìm và Thay thế chuỗi trong tất cả các file đệ quy sử dụng grep và sed

    sed: -e expression #1, char 22: unterminated `s' command 
    

    là có một vấn đề về kịch bản của tôi không? Cũng là "oldstring" có ký tự đặc biệt

    #!bin/bash 
    oldstring='<script>"[oldscript]"</script>' 
    newstring='<script>"[newscript]"</script>' 
    grep -rl $oldstring /path/to/folder | xargs sed -i s/$oldstring/$newstring/g 
    
    +1

    Dấu ngoặc vuông có thể cần phải được thoát. Ngoài ra đôi trích dẫn mô hình sed. – phs

    +3

    Bạn cũng sẽ gặp sự cố với '/' trong các mẫu của mình. Họ nên được trốn thoát. Hoặc bạn có thể sử dụng dấu phân tách khác cho lệnh 's' của bạn (ví dụ:' @ '). –

    Trả lời

    36

    Như @Didier nói, bạn có thể thay đổi dấu phân cách của bạn để một cái gì đó khác hơn /:

    grep -rl $oldstring /path/to/folder | xargs sed -i [email protected][email protected][email protected] 
    
    +5

    Ở trên sẽ thất bại trong SO nhiều cách thú vị cho rất nhiều nội dung có thể có của oldstring hoặc newstring. –

    +1

    @EdMorton, bạn vui lòng đặt một ví dụ về cách nó thất bại? Tôi biết bạn đã đăng các hình thức truyền thống làm dưới đây, nhưng chỉ nói rằng nó có thể thất bại để lại câu hỏi như thế nào. Sau đó, tôi có thể hiểu tại sao tôi nên giải pháp của bạn. Những giải pháp này có vẻ dễ dàng hơn nhiều. Cảm ơn –

    +3

    Hãy thử ở trên với bất kỳ ký tự vỏ hình cầu nào hoặc @ trong biến chuỗi. Các ký tự kết hợp có thể/sẽ khớp với tên tệp trong thư mục của bạn, nếu không phải hôm nay thì một ngày nào đó trong tương lai khi bạn mong đợi nó, và @ sẽ chấm dứt lệnh sed của bạn. Nó cũng sẽ thất bại nếu chuỗi cũ chứa khoảng trắng ở các vị trí khác nhau, chưa kể nếu chuỗi chứa ký tự dòng mới. OP đặc biệt nói 'the oldstring' có các ký tự đặc biệt', vì vậy đó là một đầu lớn cho rằng bất kỳ điều gì tôi vừa mô tả và nhiều khả năng sẽ xảy ra. –

    3

    sed biểu hiện cần phải được trích dẫn

    sed -i "s/$oldstring/$newstring/g" 
    
    4

    Những kẻ GNU REALLY đã sai lầm khi họ giới thiệu tệp đệ quy tìm kiếm grep. grep là để tìm REs trong các tập tin và in dòng phù hợp (g/re/p nhớ?) KHÔNG cho việc tìm kiếm tập tin. Có một công cụ hoàn hảo tốt với một tên rất rõ ràng cho các tập tin FINDing. Bất cứ điều gì đã xảy ra với câu thần chú UNIX làm một việc và làm tốt điều đó?

    Dù sao, dưới đây là cách bạn muốn làm những gì bạn muốn sử dụng phương pháp truyền thống UNIX (chưa được kiểm tra):

    find /path/to/folder -type f -print | 
    while IFS= read -r file 
    do 
        awk -v old="$oldstring" -v new="$newstring" ' 
         BEGIN{ rlength = length(old) } 
         rstart = index($0,old) { $0 = substr($0,rstart-1) new substr($0,rstart+rlength) } 
         { print } 
        ' "$file" > tmp && 
        mv tmp "$file" 
    done 
    

    Không phải là bằng cách sử dụng awk/index() thay vì sed và grep bạn tránh được sự cần thiết phải thoát khỏi tất cả các metacharacters RE có thể xuất hiện trong chuỗi cũ hoặc chuỗi mới của bạn cộng với một ký tự để sử dụng làm dấu phân cách sed không thể xuất hiện trong chuỗi cũ hoặc mới của bạn và bạn không cần chạy grep kể từ khi thay thế sẽ chỉ xảy ra cho các tập tin có chứa chuỗi bạn muốn. Có nói tất cả điều đó, nếu bạn không muốn các dấu thời gian tập tin để thay đổi nếu bạn không sửa đổi các tập tin, sau đó chỉ cần làm một diff trên tmp và tập tin ban đầu trước khi làm mv hoặc ném trong một fgrep -q trước khi awk.

    Lưu ý: Phần trên sẽ không hoạt động đối với tên tệp có chứa dòng mới. Nếu bạn có những điều đó thì hãy cho chúng tôi biết và chúng tôi có thể chỉ cho bạn cách xử lý chúng.

    +2

    +1 Khi ai đó nói về việc sử dụng 'sed' với' grep', có một cơ hội tuyệt vời mà họ nên sử dụng chỉ là 'sed' hoặc chuyển sang' awk'. Bằng cách này, nếu bạn sử dụng '-print0' trong tìm kiếm của bạn, và (trong BASH) sử dụng' -d \ 0' nên chăm sóc tên tập tin với các dòng mới trong chúng. –

    +0

    @DavidW. Đúng.Và khi bạn bắt đầu nói về thoát metacharacters RE để sed hoặc grep không đối xử với họ như vậy, sau đó bạn cần phải chuyển sang awk/index() hoặc fgrep để bạn có thể tìm kiếm các chuỗi thay vì REs. –

    +0

    @josten '-r' arg cho' grep' là một thay thế cho việc sử dụng 'find' không sử dụng' awk'. Bạn có thể sử dụng 'awk' với' find + xargs' thay vì 'grep + sed' và kết quả sẽ thường ngắn gọn và hiệu quả hơn. Sử dụng 'awk' chắc chắn sẽ không khiến bạn tạo ra một lớp lót phức tạp. –

    9
    grep -rl $oldstring . | xargs sed -i "s/$oldstring/$newstring/g" 
    
    +0

    Vì vậy, các biến chứng với điều này, là các tập tin với không gian trong tên của họ sẽ không được chọn. Nếu bạn có "/ files/File Two.txt", sed sẽ thử "/ files/File" và "Two.txt". – Captainlonate

    -1
    grep -rl SOSTITUTETHIS . | xargs sed -Ei 's/(.*)SOSTITUTETHIS(.*)/\1WITHTHIS\2/g' 
    

     Các vấn đề liên quan

    • Không có vấn đề liên quan^_^