Khái niệm về 'Không gian giữ' và 'Không gian mẫu' trong Sed


86

Tôi bối rối bởi hai khái niệm trong sed: giữ không gian và không gian mẫu. Ai đó có thể giúp giải thích chúng?

Đây là một đoạn hướng dẫn sử dụng:

h H    Copy/append pattern space to hold space.
g G    Copy/append hold space to pattern space.

n N    Read/append the next line of input into the pattern space.

Sáu lệnh này thực sự làm tôi bối rối.


4
Thử nó cho mình:echo $'1\n2\n3\n4' | sed -n '1~2h;2~2{p;x;p}'
choroba

4
Đừng nhầm lẫn, chỉ cần không sử dụng chúng. Đối với bất kỳ điều gì khác ngoài các thay thế đơn giản trên một dòng, bạn nên sử dụng awk, không phải sed. Giữ khoảng trắng, khoảng trắng mẫu và 95% cấu trúc ngôn ngữ sed được phát minh trước awk khi không có giải pháp thay thế nào tốt hơn. Chúng đã trở nên lỗi thời ngay sau khi awk được phát minh vào giữa những năm 1970 và chỉ còn tồn tại cho đến ngày nay bởi những người thích giải quyết vấn đề bằng cách sử dụng cú pháp phức tạp của seds thay vì làm nó đơn giản và quan trọng trong awk. Nếu bạn đang sử dụng nhiều hơn s, g và p (với -n) trong sed thì gần như chắc chắn bạn đang sử dụng sai công cụ.
Ed Morton

26
Morton awk hoạt động với dữ liệu có cấu trúc (mỗi dòng có cấu trúc giống nhau). Sed có nghĩa là làm việc với dữ liệu ngẫu nhiên thô. Vì vậy, bạn không thể chỉ đơn giản sử dụng awk thay vì sed.
Pithikos

5
Tôi thực sự khuyên bạn nên đọc info sed. Nó chi tiết hơn nhiều so với trang người trần.
Fernando Basso

4
Tôi đồng ý với Pithikos. Tôi đi xuống làn đường như Morton đã làm, và tự hỏi mình câu hỏi giống như Morton đã làm. Tuy nhiên, tôi vẫn chưa thể loại bỏ sed một cách dễ dàng.
eigenfield

Câu trả lời:


111

Khi sed đọc một dòng tập tin bằng cách dòng, dòng đã được hiện đọc được đưa vào mô hình đệm (không gian mẫu). Bộ đệm mẫu giống như bộ đệm tạm thời, bàn di chuột nơi lưu trữ thông tin hiện tại. Khi bạn yêu cầu sed in, nó sẽ in bộ đệm mẫu.

Không gian lưu trữ / lưu trữ bộ đệm giống như một kho lưu trữ dài hạn, như vậy bạn có thể lấy một thứ gì đó, lưu trữ nó và sử dụng lại sau khi sed đang xử lý một dòng khác. Bạn không xử lý trực tiếp vùng lưu giữ, thay vào đó, bạn cần sao chép nó hoặc thêm vào vùng mẫu nếu bạn muốn làm gì đó với nó. Ví dụ, lệnh in chỉ pin khoảng trống mẫu. Tương tự như vậy, shoạt động trên không gian mẫu.

Đây là một ví dụ:

sed -n '1!G;h;$p'

(tùy chọn -n ngăn tự động in các dòng)

Có ba lệnh ở đây: 1!G, h$p. 1!Gcó một địa chỉ, 1(dòng đầu tiên), nhưng !có nghĩa là lệnh sẽ được thực thi ở mọi nơi trừ trên dòng đầu tiên. $pmặt khác sẽ chỉ được thực hiện ở dòng cuối cùng. Vậy điều gì xảy ra là:

  1. dòng đầu tiên được đọc và tự động chèn vào không gian mẫu
  2. trên dòng đầu tiên, lệnh đầu tiên không được thực hiện; hsao chép dòng đầu tiên vào không gian lưu giữ .
  3. bây giờ dòng thứ hai thay thế bất cứ thứ gì trong không gian mẫu
  4. trên dòng thứ hai, đầu tiên chúng ta thực thi G, nối nội dung của bộ đệm lưu vào bộ đệm mẫu, phân tách nó bằng một dòng mới. Không gian mẫu hiện chứa dòng thứ hai, dòng mới và dòng đầu tiên.
  5. Sau đó, hlệnh chèn nội dung được ghép nối của vùng đệm mẫu vào vùng lưu giữ, hiện giữ các dòng đảo ngược hai và một.
  6. Chúng ta tiếp tục đến dòng số ba - chuyển đến điểm (3) ở trên.

Cuối cùng, sau khi dòng cuối cùng đã được đọc và không gian lưu giữ (chứa tất cả các dòng trước đó theo thứ tự ngược lại) đã được thêm vào không gian mẫu, không gian mẫu được in với p. Như bạn đã đoán, phần trên thực hiện chính xác những gì taclệnh thực hiện - in ngược lại tệp.


3
Tùy chọn G và h có hoạt động giống như "cắt và nối" không ?? Nó không giống như hoạt động "sao chép và nối".
Smile

Điều gì gắn với mẫu và giữ khoảng cách khi các lệnh lồng nhau (dấu ngoặc nhọn) được sử dụng? '195,210{/add/p}'… Có thể trích xuất dòng cuối cùng của một nhóm dòng liên quan đến một mẫu không?
Sandburg

17

@Ed Morton: Tôi không đồng ý với bạn ở đây. Tôi thấy sedrất hữu ích và đơn giản (một khi bạn tìm hiểu khái niệm về mô hình và giữ bộ đệm) để tìm ra một cách thanh lịch để thực hiện chuyển đổi đa dòng.

Ví dụ, chúng ta hãy lấy một tệp văn bản có tên máy chủ và một số thông tin về mỗi máy chủ lưu trữ, với rất nhiều rác ở giữa mà tôi không quan tâm.

Host: foo1
some junk, doesnt matter
some junk, doesnt matter
Info: about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Info: a second line about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Host: foo2
some junk, doesnt matter
Info: about foo2 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter

Đối với tôi, một tập lệnh awk để chỉ lấy các dòng có tên máy chủ và infodòng tương ứng sẽ mất nhiều hơn một chút so với những gì tôi có thể làm với sed:

sed -n '/Host:/{h}; /Info/{x;p;x;p;}' myfile.txt

đầu ra trông giống như:

Host: foo1
Info: about foo1 that I really care about!!
Host: foo1
Info: a second line about foo1 that I really care about!!
Host: foo2
Info: about foo2 that I really care about!!

(Lưu ý rằng nó Host: foo1xuất hiện hai lần trong đầu ra.)

Giải trình:

  1. -n tắt đầu ra trừ khi được in rõ ràng
  2. kết hợp đầu tiên, tìm và đặt Host:dòng vào bộ đệm giữ (h)
  3. khớp thứ hai, tìm dòng Info: tiếp theo, nhưng trước tiên trao đổi (x) dòng hiện tại trong bộ đệm mẫu với bộ đệm giữ và in (p) Host:dòng, sau đó trao đổi lại (x) và in (p) dòng Info:.

Vâng, đây là một ví dụ đơn giản, nhưng tôi nghi ngờ đây là một vấn đề phổ biến đã được xử lý nhanh chóng bởi một lớp lót sed đơn giản. Đối với các nhiệm vụ phức tạp hơn nhiều, chẳng hạn như những nhiệm vụ mà bạn không thể dựa vào một trình tự nhất định, có thể dự đoán được, awk có thể phù hợp hơn.


2
Trong trường hợp này, mặc dù bạn chỉ có thể sử dụng grep:grep 'Host\|Info'
Pithikos

Nếu có hai dòng Thông tin sau một Máy chủ nhất định, thì @JensJenson muốn cả hai dòng Thông tin được đặt trước một dòng Thông tin. Tôi nghĩ tôi sẽ chỉnh sửa câu trả lời cho phù hợp. Pithikos, grep sẽ không đủ khi đó.
Aaron McDaid,

3
@JensJenson thì awktương đương với mã sed của bạn là khá ngắn quá:awk '/Host:/{hold=$0}; /Info/{print hold; print;}' myfile.txt
Aaron McDaid

11

Mặc dù câu trả lời của @ January và ví dụ rất hay, nhưng với tôi lời giải thích vẫn chưa đủ. Tôi đã phải tìm kiếm và học hỏi rất nhiều cho đến khi tôi hiểu được cách thức sed -n '1!G;h;$p'hoạt động chính xác . Vì vậy, tôi muốn nói rõ hơn về lệnh cho một người như tôi.

Trước hết, chúng ta hãy xem lệnh làm gì.

$ echo {a..d} | tr ' ' '\n' # Prints from 'a' to 'd' in each line
a
b
c
d
$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;$p'
d
c
b
a

Nó đảo ngược đầu vào giống như taclệnh.

sedđọc từng dòng, vì vậy hãy xem điều gì xảy ra trên khoảng trống vỗkhông gian giữ ở mỗi dòng. Khi hlệnh sao chép nội dung của không gian mẫu vào không gian lưu giữ, cả hai không gian đều có cùng văn bản.

Read line    Pattern Space / Hold Space    Command executed
-----------------------------------------------------------
a            a$                            h
b            b\na$                         1!G;h
c            c\nb\na$                      1!G;h
d            d\nc\nb\na$                   1!G;h;$p

Ở dòng cuối cùng, $pcác bản in d\nc\nb\na$được định dạng thành

d
c
b
a

Nếu bạn muốn xem không gian mẫu cho mỗi dòng, bạn có thể thêm một llệnh.

$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;l;$p'
a$
b\na$
c\nb\na$
d\nc\nb\na$
d
c
b
a

Tôi thấy rất hữu ích khi xem video hướng dẫn này Hiểu cách hoạt động của sed , vì anh chàng chỉ ra cách từng không gian sẽ được sử dụng từng bước. Khoảng cách giữ được đề cập trong hướng dẫn thứ 4, nhưng tôi khuyên bạn nên xem tất cả các video nếu bạn chưa quen sed.

Ngoài ra tài liệu về GNU sedhướng dẫn về Sed của Bruce Barnett là những tài liệu tham khảo rất tốt.


2
Tôi nghĩ rằng nó cũng sẽ hữu ích khi đề cập rằng không gian lưu trữ cho tất cả các mục đích thực tế là trống trừ khi chúng tôi thêm một cái gì đó vào đó.
Giữa
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.