Làm cách nào để thay đổi mã ^ L trong nhiều tệp trong Ubuntu?


8

Tôi có rất nhiều tệp XML, hơn 50000 tệp.

Trong một số tệp XML, một số tệp được viết như thế này

<filename>abc.JPEG<^Lilename>

^Lchỉ là một ký tự, nhưng tôi không thể tìm thấy ý ^Lnghĩa của Google.

Khi tôi sử dụng catđể in nội dung của tệp, nó sẽ hiển thị như sau

<filename>abc.JPEG<
                   ilename>

Dù sao, tôi muốn đổi <filename>abc.JPEG<^Lilename>thành<filename>abc.JPEG</filename>

Tôi đã tìm thấy một số lệnh để thay đổi một từ trong nhiều tệp, chẳng hạn như

find . -exec perl -pi -e 's/[find_word]/[change_word]/g' {} \;

Nhưng lệnh đó không hoạt động trong trường hợp của tôi, vì nó không thể nhận ra từ tìm kiếm khi tôi vừa gõ ^L.

Làm thế nào tôi có thể thay đổi <filename>abc.JPEG<^Lilename>thành <filename>abc.JPEG</filename>nhiều tập tin?


6
Rõ ràng ai đó đã sử dụng <\filename>thay vì </filename>trong một bối cảnh \fsẽ được hiểu là nhân vật nguồn cấp dữ liệu. Bạn có thể nên theo dõi nguồn của các tệp này và chỉ ra vấn đề với công cụ tạo của chúng cho nhà phát triển. Để sửa các tập tin, câu trả lời được chấp nhận là tốt.
Hans-Martin Mosner

Câu trả lời:


17

Control-L (đại diện là ^L) là ký tự "form feed". Trong ASCII, nó có giá trị thập phân 12 ( Llà chữ cái thứ 12 của bảng chữ cái) hoặc giá trị hex 0c:

$ printf 'foo\x0cbar\n' | cat -et
foo^Lbar$

$ printf 'foo\x0cbar\n'
foo
   bar

Bạn có thể thay thế nó bằng các công cụ như sed bằng cách chỉ định mã thoát thập lục phân:

$ printf 'foo\x0cbar\n' | sed 's/\x0c//'
foobar

Hoặc, soạn ^Ltrực tiếp bằng trình tự bàn phím CTRL+ V CTRL+L

sed 's/CTRL+VCTRL+L//'

Để thay thế cụ thể của bạn, đưa ra

$ printf '<\x0cilename\n'
<
 ilename

sau đó

$ printf '<\x0cilename\n' | sed 's/<\x0c/<\/f/g'
</filename

(công cụ gsửa đổi được thêm vào trong trường hợp có nhiều hơn một phiên bản trên mỗi dòng).


Trong trường hợp của tôi, "$ printf '<\ x0cilename \ n' | sed 's / <\ x0c / <\\ f / g'" không hoạt động. Nhưng, theo câu trả lời của bạn, "$ find. -Exec perl -pi -e 's / <\ x0cilename> / <\ / tên tệp> / g' {} \;" hoạt động tốt Cảm ơn câu trả lời của bạn :)
Yang

@Yang xin lỗi, tôi chỉ nhận ra rằng tôi đã nhầm lẫn giữa dấu gạch chéo và dấu gạch chéo ngược trong câu trả lời của mình (đã sửa ngay bây giờ) - vẫn không chắc tại sao điều đó lại ngăn phiên bản sed hoạt động mặc dù
Steeldo

Một câu trả lời rất hay! Sẽ tốt hơn nữa nếu nó bao gồm nói rằng một findvòng lặp trên 50000 tệp XML đó và tự động xử lý từng tệp (và cũng tạo một bản sao lưu).
Kingsley

2

Như Hans-Martin Mosner đã chỉ ra trong các bình luận, có vẻ như ai đó đã sử dụng dấu gạch chéo ngược thay vì dấu gạch chéo về phía trước khi tạo XML (hoặc có thể chạy toàn bộ <filename>phần thông qua trình chuyển đổi Unix sang Windows quá nhiệt tình về dấu gạch chéo). \flà một chuỗi thoát hiếm khi được sử dụng cho một ký tự nguồn cấp dữ liệu, còn gọi là U + 0C hoặc ^ L. Vì vậy, một số bước sau của đường ống sau đó thay thế bằng các \fký tự U + 0C theo nghĩa đen.

May mắn thay, U + 0C là một ký tự cực kỳ hiếm mà không thể tìm thấy có chủ ý trong bất kỳ loại XML nào. Và kể từ khi chỉ \fsẽ tạo ra này, như trái ngược với (nói) \ghoặc \k, một phát hiện và thay thế phổ biến nên khắc phục không chỉ </filename>mà còn </folder>, </file>hoặc bất cứ điều gì khác mà đã đọc sai.

Đó là những gì kịch bản sed của Steeldo làm; Tôi chỉ làm cho nó chung chung hơn một chút:

sed 's|\x0c|/f|g'

Điều này có nghĩa là "(s) wap tất cả các trường hợp của \x0c(nghĩa là, U + 0C) đến /f, (g) lobally".


2

\flà ký tự nguồn cấp dữ liệu trong Perl. Dường như các tệp không đúng định dạng này được tạo bởi một người mới đối với cả Perl và XML.

Đây là một bản sửa lỗi trước đây - cũng đáp ứng các mục tiêu của OP là tự động cập nhật tất cả các tệp, không giống như câu trả lời được chấp nhận với sed, sẽ chỉ hoạt động trên một tệp tại một thời điểm mà nó không được ghép nối find.

\fchỉ có thể được sử dụng chính nó thay vì mã thập lục phân x0c.

find . -type f -exec perl -pi.bkp -e 's [ \f ilename ][ /f ilename ]gx' {} \;

Ở đây tôi đã thêm -type fvào tel findđể chỉ trả về các tệp đơn giản - nếu không findsẽ trả về .trong danh sách và kích hoạt cảnh báo khi bạn cố chỉnh sửa nó, mặc dù mọi thứ khác vẫn sẽ hoạt động.

Tôi cũng đã làm cho regex dễ nhìn hơn bằng cách sử dụng xcờ bỏ qua khoảng trắng thực, cho phép bạn loại bỏ các phần tử của biểu thức chính quy của bạn. Nếu bạn không thích điều này, thì ở đây không có:

find . -type f -exec perl -pi.bkp -e 's[\filename][/filename]g' {} \;

Và trong trường hợp có khả năng tất cả các ký tự nguồn cấp dữ liệu là giả và tất cả phải được thay thế bằng /f, sau đó bạn có thể làm mỏng lớp lót xuống hơn nữa:

find . -type f -exec perl -pi.bkp -e 's[\f][/f]g' {} \;

Bạn không cần phải sử dụng dấu gạch chéo về phía trước để bao quanh các phần tử của lệnh thay thế regex ( s///) trong Perl. Bạn có thể sử dụng bất kỳ biểu tượng. Tuy nhiên, nếu bạn chọn sử dụng bất kỳ loại biểu tượng giống như khung được ghép nối nào, bạn phải sử dụng cả hai loại này: s[old][new]ví dụ.

Vì tôi không sử dụng dấu gạch chéo, tôi không phải thoát bất kỳ dấu gạch chéo nào.

Đối với -i.bkp: perl -pi -echo phép bạn chỉnh sửa tại chỗ - nhưng nếu bạn muốn có thêm bảo hiểm trong trường hợp bạn gặp lỗi chương trình Perl tìm và thay thế, bạn có thể đặt một phần mở rộng tệp để nó tạo một bản sao của các tệp gốc cho bạn. Ở đây, tôi đã sử dụng .bkp.

Trong các phiên bản gần đây nhất của Perl, chỉnh sửa tại chỗ đã được cập nhật để trở nên linh hoạt hơn trong trường hợp hệ thống của bạn gặp sự cố nghiêm trọng như mất điện hoặc hết dung lượng đĩa. Đây là tác giả Perl brian d foy về cải tiến tại chỗ được cải thiện trong Perls gần đây.

Bạn nên cân nhắc sử dụng Perl cho các loại nhiệm vụ này, vì đây là ngôn ngữ lập trình đa năng cực kỳ mạnh mẽ nhưng được đánh giá thấp, một trong những mục tiêu thiết kế ban đầu của nó là thay thế sedawkbằng thứ gì đó tốt hơn nhiều.

Khả năng phù hợp với regex Perl 5 và cải thiện cú pháp regex vượt xa những người sed, awkvà trên thực tế tất cả các ngôn ngữ lập trình khác nhau từ Perl 6, làm cho Perl lựa chọn hợp lý nhất cho cả hai đơn giản và thao tác regex tiên tiến.

Để làm rõ: sedcũng sẽ hoạt động tốt findvà bạn cũng có thể sử dụng sed -i.bkpđể tạo bản sao lưu của từng tệp được chỉnh sửa, nhưng theo tôi biết thì nó không có tính năng phục hồi bổ sung trong Perl 5.28 trở lên. Nó cũng sử dụng cú pháp regex UNIX ® truyền thống mạnh mẽ và kém mạnh mẽ hơn nhiều.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.