Grep để tìm đúng dòng, sed để thay đổi nội dung, sau đó đưa nó trở lại vào tập tin gốc?


9

Tôi đang cố gắng thay đổi một từ trên một dòng cụ thể trong một tệp, nhưng tôi gặp một số khó khăn khi kết nối tất cả lại với nhau.

Về cơ bản, trên một dòng trong tệp của tôi có từ khóa 'firmware numvision' và trên dòng này (và chỉ dòng này) tôi muốn thay thế từ 'thử nghiệm' bằng từ 'sản xuất'.

Vì vậy, tôi có thể làm điều này:

grep 'firmware_revision' myfile.py | sed 's/test/production'

Điều này sẽ chọn ra dòng tôi muốn và thực hiện thay thế, nhưng tôi không thể tìm ra cách đưa dòng mới này vào tệp gốc để thay thế dòng cũ. Tôi rõ ràng không thể chuyển hướng nó trở lại tập tin, vậy tôi phải làm sao?

Ngay cả khi tôi sử dụng tạm thời, bằng cách sử dụng grepđể chỉ lấy dòng tôi cần, tôi sẽ mất tất cả các dữ liệu khác trong tệp, vì vậy tôi không còn có thể chuyển hướng tất cả sang tệp tạm thời sau đó thay thế bản gốc bằng temp.

Chỉnh sửa - Ai đó hỏi thêm thông tin

Hãy nói rằng tôi có một tập tin đầy đủ các dòng như thế này

[
  ('key_name1', str, 'value1', 'Description'),
  ('key_name2', str, 'value2', 'Description'),
  ('key_name3', str, 'value3', 'Description'),
  ('firmware_revision', str, 'my-firmware-name-test', 'Firmware revision name')
]

bây giờ tôi muốn viết một tập lệnh (lý tưởng là một lớp lót) sẽ tìm ra dòng có chứa 'firmware numvision' và thay đổi tất cả các trường hợp của từ 'test' trên dòng đó thành 'sản xuất'. Từ 'kiểm tra' có thể ở những nơi khác trong tệp đó và tôi không muốn chúng thay đổi. Vì vậy, để rõ ràng, tôi muốn thay đổi dòng trên

('firmware_revision', str, 'my-firmware-name-production', 'Firmware revision name')

Làm thế nào để tôi làm điều này?


5
sedlà rất mạnh mẽ, nó có thể thực hiện cả hai chức năng ( grepvà thay thế) nhưng chúng tôi sẽ cần thêm thông tin về cách dòng trông như thế nào để giúp bạn.
hóa học

Tôi sẽ thêm thông tin vào bài viết gốc
John Allard

7
Hãy thử:sed -i.bak '/firmware_revision/ s/test/production/' myfile.py
John1024

1
Ah nó hoạt động hoàn hảo! Bạn có thể giải thích cú pháp?
John Allard

@ John John rất tốt. Tôi đã thêm một câu trả lời với lời giải thích.
John1024

Câu trả lời:


22

Thử:

sed -i.bak '/firmware_revision/ s/test/production/' myfile.py

Ở đây, /firmware_revision/hoạt động như một điều kiện. Điều này đúng với các dòng khớp với regex firmware_revisionvà false cho các dòng khác. Nếu điều kiện là đúng, thì lệnh tiếp theo sẽ được thực thi. Trong trường hợp này, lệnh đó là lệnh thay thế thay thế lần xuất hiện đầu tiên của testvới production.

Nói cách khác, lệnh chỉ s/test/production/được thực thi trên các dòng khớp với biểu thức chính quy firmware_revision. Tất cả các dòng khác đi qua không thay đổi.

Theo mặc định, sed gửi đầu ra của nó ra tiêu chuẩn. Bạn, tuy nhiên, muốn thay đổi tập tin tại chỗ. Vì vậy, chúng tôi đã thêm -itùy chọn. Cụ thể, -i.baklàm cho tập tin được thay đổi tại chỗ với một bản sao lưu được lưu với một .bakphần mở rộng.

Nếu bạn đã quyết định rằng lệnh hoạt động cho bạn và bạn muốn sống nguy hiểm và không tạo bản sao lưu, thì với GNU sed (Linux), hãy sử dụng:

sed -i '/firmware_revision/ s/test/production/' myfile.py

Ngược lại, trên BSD (OSX), -itùy chọn phải có đối số. Nếu bạn không muốn giữ một bản sao lưu, hãy cung cấp cho nó một đối số trống. Do đó, sử dụng:

sed -i '' '/firmware_revision/ s/test/production/' myfile.py

Biên tập

Trong phần chỉnh sửa cho câu hỏi, OP yêu cầu mọi sự xuất hiện của testdòng được thay thế bằng production. Trong trường hợp đó, chúng tôi thêm gtùy chọn vào lệnh thay thế cho thay thế toàn cầu (cho dòng đó):

sed -i.bak '/firmware_revision/ s/test/production/g' myfile.py

5
Để đầy đủ, bạn có thể muốn giải thích -i.bakphần này là tốt.
Stephen Harris

5
@StephenHarris Điểm tốt. Giải thích -ithêm.
John1024

Tôi cảm thấy bạn có thể có thể chạm tới các vì sao, chỉ cần đứng trên cuốn sách giải thích tất cả những điều sedcó thể làm ...
KlaymenDK

@ John1024 Đối với không BSD mọi người, bạn có thể thêm những lý do đầu tiên ''sau -i?
Hastur

3
OP muốn thay đổi tất cả các trường hợp của từ 'thử nghiệm' trên dòng đó thành 'sản xuất' . Điều quan trọng là nối / g vào lệnh sed trong trường hợp này: sed -i '/firmware_revision/ s/test/production/g' myfile.pynếu không thì chỉ có trường hợp đầu tiên được thay đổi.
quỳ

4

Trên các máy cũ có trường cũ sedkhông có tùy chọn hỗ trợ -i:

TF=$( mktemp -t "${0##*/}"_$$_XXXXXXXX ) && \
trap 'rm -f "$TF"' EXIT HUP INT QUIT TERM && \
sed '/firmware_revision/ s/test/production/' myfile.py >"$TF" && \
mv -f "$TF" myfile.py

1
Trên những máy cũ hơn, bạn chỉ cần sử dụng edvà thực hiện trong một dòng:printf %s\\n g/firmware_revision/s/test/production/g w q | ed -s myfile.py
don_crissti

1
@don_crissti Rất đúng, nhưng ed(1)không cung cấp bất kỳ lý do nào để hiển thị việc sử dụng mktemp(1).
Satō Katsura

Nếu bạn đang sử dụng tempfile, bạn cũng có thể giữ inode và perms của tệp gốc, giống như edvậy. Thay vì mv -f "$TF" myfile.plsử dụng cat "$TF" > myfile.pl && rm -f "$TF". BTW, đó là một cách thực hành tốt để sử dụng tên biến chữ thường ( $tfthay vì $TF), chúng được đảm bảo không xung đột với bất kỳ lọ đựng bash tích hợp nào (có thể là các vỏ bourne khác).
cas

@cas Re :: cat "$TF" > myfile.plhãy thử điều này: touch a b; chmod 0444 a; cat b >a(BTW, sed -isẽ không hoạt động trong trường hợp đó). Tốt hơn để người dùng đối phó với điều đó. Re :: rm -f "$TF"không cần thiết, xem trap ... EXIT. Re: $tfthay vì $TF: có thể; đó là một vấn đề về phong cách.
Satō Katsura

Đó là hành vi bình thường và dự kiến ​​của các quyền unix. Quan điểm của tôi là việc tạo một tệp mới và chuyển nó qua bản gốc 1. sẽ tạo ra một nút mới cho tên tệp đó (phá vỡ mọi liên kết cứng). 2. có thể thay đổi perm, nếu hiện tại umask khác với perm ban đầu. Đối với các chữ hoa chữ thường, đó không chỉ là vấn đề về kiểu dáng - rất nhiều người đã mắc sai lầm khi sử dụng chữ hoa PATH hoặc RANDOM hoặc SHELL hoặc bất cứ điều gì cho các biến của chính họ đã phát hiện ra một cách khó khăn. (và vâng, tôi thường sử dụng bình hoa chữ thường. Tôi biết điều đó sai, tôi đang cố gắng phá vỡ thói quen này).
cas
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.