Tôi đồng ý với bạn - nó có thể là một vấn đề chung chung. Một số tiện ích phổ biến có một số cơ sở để xử lý nó, mặc dù.
nl
nl
, ví dụ, phân tách đầu vào thành các trang logic như được phân tách bằng dấu phân cách-d
hai phần ký tự . Ba lần xuất hiện trên một dòng tất cả chỉ ra sự bắt đầu của một tiêu đề , hai cơ thể và một chân trang . Nó thay thế bất kỳ thứ nào được tìm thấy trong đầu vào bằng một dòng trống ở đầu ra - đó là những dòng trống duy nhất mà nó từng in
Tôi đã thay đổi ví dụ của bạn để bao gồm một phần khác và đưa nó vào ./infile
. Vì vậy, nó trông như thế này:
line A
line B
@@inline-code-start
line X
line Y
line Z
@@inline-code-end
line C
line D
@@start
line M
line N
line O
@@end
Sau đó, tôi chạy như sau:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end$/@@/' <infile |
nl -d@@ -ha -bn -w1
nl
có thể được yêu cầu tích lũy trạng thái trên các trang logic, nhưng nó không theo mặc định. Thay vào đó, nó sẽ đánh số các dòng đầu vào của nó theo kiểu và theo phần . Vì vậy, -ha
có nghĩa là số tất cả các dòng tiêu đề và -bn
có nghĩa là không có dòng cơ thể - vì nó bắt đầu trong trạng thái cơ thể .
Cho đến khi tôi học tôi này sử dụng để sử dụng nl
cho bất kỳ đầu vào, nhưng sau khi nhận ra rằng nl
sản lượng có thể bóp méo theo mặc định của nó -d
elimiter \:
Tôi đã học được để cẩn thận hơn với nó và bắt đầu sử dụng grep -nF ''
cho đầu vào chưa được kiểm tra để thay thế. Nhưng một bài học khác được học ngày hôm đó là nl
có thể được áp dụng rất hữu ích ở các khía cạnh khác - chẳng hạn như điều này - nếu bạn chỉ sửa đổi đầu vào của nó một chút - như tôi đã làm vớised
ở trên.
ĐẦU RA
line A
line B
1 line X
2 line Y
3 line Z
line C
line D
1 line M
2 line N
3 line O
Dưới đây là một số thông tin khác nl
- bạn có để ý ở trên cách tất cả các dòng trừ những dòng được đánh số bắt đầu bằng dấu cách không? Khi nl
các dòng số, nó sẽ chèn một số ký tự nhất định vào đầu mỗi ký tự. Đối với những dòng đó, nó không phải là số - thậm chí là khoảng trắng - nó luôn khớp với thụt lề bằng cách chèn ( -w
số thứ tự + -s
khoảng cách len) * khoảng trắng ở đầu các dòng không đánh số. Điều này cho phép bạn tái tạo chính xác nội dung không được đánh số bằng cách so sánh nó với nội dung được đánh số - và với rất ít nỗ lực. Khi bạn xem xét điều đó nl
sẽ chia đầu vào của nó thành các phần hợp lý cho bạn và bạn có thể chèn các -s
dấu tùy ý vào đầu mỗi dòng mà nó đánh số, thì việc xử lý đầu ra của nó khá dễ dàng:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end/@@/; t
s/^\(@@\)\{1,3\}$/& /' <infile |
nl -d@@ -ha -bn -s' do something with the next line!
'
Các bản in trên ...
line A
line B
1 do something with the next line!
line X
2 do something with the next line!
line Y
3 do something with the next line!
line Z
line C
line D
1 do something with the next line!
line M
2 do something with the next line!
line N
3 do something with the next line!
line O
GNU sed
Nếu nl
không phải là ứng dụng đích của bạn, thì GNU sed
có thể e
xecute một lệnh shell tùy ý cho bạn tùy thuộc vào một trận đấu.
sed '/^@@.*start$/!b
s//nl <<\\@@/;:l;N
s/\(\n@@\)[^\n]*end$/\1/
Tl;e' <infile
Ở trên sed
thu thập đầu vào trong không gian mẫu cho đến khi nó đủ để vượt qua thành công T
est thay thế và ngừng b
trang trại trở lại :l
abel. Khi có, nó e
xecutes nl
với đầu vào được biểu diễn dưới dạng<<
tài liệu ở đây cho tất cả phần còn lại của không gian mẫu.
Quy trình làm việc là như thế này:
/^@@.*start$/!b
- nếu một
^
toàn bộ dòng $
nào !
không /
phù hợp với /
mô hình trên, sau đó nó được b
ranched ra của kịch bản và autoprinted - vì vậy từ thời điểm này trở đi chúng tôi chỉ làm việc với một loạt các dòng bắt đầu với mô hình.
s//nl <<\\@@/
- trống
s//
trường /
đứng cho địa chỉ cuối cùng sed
cố gắng để phù hợp - vì vậy lệnh này thay thế toàn bộ @@.*start
dòng cho nl <<\\@@
thay thế.
:l;N
- Các
:
lệnh định nghĩa một nhãn chi nhánh - ở đây tôi thiết lập một tên :l
Abel. Lệnh N
ext nối thêm dòng đầu vào tiếp theo vào không gian mẫu theo sau là \n
ký tự ewline. Đây là một trong một vài cách để có được một \n
ewline trong một sed
không gian mẫu - \n
ký tự ewline là một dấu phân cách chắc chắn cho một sed
der người đã làm nó một lúc.
s/\(\n@@\)[^\n]*end$/\1/
s///
ubstlation này chỉ có thể thành công sau khi bắt đầu và chỉ trong lần xuất hiện đầu tiên sau của dòng kết thúc . Nó sẽ chỉ hoạt động trên một không gian mẫu trong đó \n
ewline cuối cùng ngay lập tức được theo sau bằng cách @@.*end
đánh dấu phần cuối $
của không gian mẫu. Khi nó hoạt động, nó thay thế toàn bộ chuỗi khớp với nhóm \1
đầu tiên , hoặc .\(
\)
\n@@
Tl
- các
T
lệnh est ngành nhãn (nếu được cung cấp) nếu một thay thành công đã không xảy ra kể từ lần cuối cùng một dòng đầu vào đã được kéo vào không gian mô hình (như tôi làm w / N
) . Điều này có nghĩa là mỗi khi một \n
ewline được gắn vào không gian mẫu không khớp với dấu phân cách cuối của bạn, T
lệnh est sẽ thất bại và phân nhánh trở lại :l
abel, dẫn đến sed
kéo theo N
dòng ext và lặp cho đến khi thành công.
e
Khi thay thế cho kết thúc trận đấu thành công và tập lệnh không phân nhánh trở lại cho một T
est bị lỗi , sed
sẽ e
thực hiện một lệnh l
giống như thế này:
nl <<\\@@\nline X\nline Y\nline Z\n@@$
Bạn có thể thấy điều này cho chính mình bằng cách chỉnh sửa dòng cuối cùng ở đó để trông như thế nào Tl;l;e
.
Nó in:
line A
line B
1 line X
2 line Y
3 line Z
line C
line D
1 line M
2 line N
3 line O
while ... read
Một cách cuối cùng để làm điều này, và có thể là cách đơn giản nhất, là sử dụng một while read
vòng lặp, nhưng vì lý do chính đáng. Vỏ - (đặc biệt là bash
vỏ) - thường khá tuyệt vời khi xử lý đầu vào với số lượng lớn hoặc trong dòng ổn định. Điều này cũng có ý nghĩa - công việc của shell là xử lý ký tự đầu vào theo ký tự và gọi các lệnh khác có thể xử lý các nội dung lớn hơn.
Nhưng quan trọng về vai trò của nó là vỏ không được vượt read
quá đầu vào - nó được chỉ định không đệm đầu vào hoặc đầu ra đến mức nó tiêu thụ quá nhiều hoặc không chuyển tiếp đủ thời gian mà các lệnh mà nó gọi bị thiếu - đến byte. Vì vậy, read
làm cho một bài kiểm tra đầu vào tuyệt vời - đểreturn
biết thông tin về việc liệu còn đầu vào còn lại hay không và bạn nên gọi lệnh tiếp theo để đọc nó - nhưng nói chung nó không phải là cách tốt nhất để đi.
Tuy nhiên, đây là một ví dụ về cách người ta có thể sử dụng read
và các lệnh khác để xử lý đồng bộ hóa đầu vào:
while IFS= read -r line &&
case $line in (@@*start) :;; (*)
printf %s\\n "$line"
sed -un "/^@@.*start$/q;p";;
esac;do sed -un "/^@@.*end$/q;=;p" |
paste -d: - -
done <infile
Điều đầu tiên xảy ra cho mỗi lần lặp là read
kéo theo một dòng. Nếu thành công, điều đó có nghĩa là vòng lặp chưa đạt EOF và do đó, trong vòng case
khớp với dấu phân cách bắt đầu , do
khối sẽ được thực thi ngay lập tức. Khác, printf
in $line
nó read
và sed
được gọi.
sed
sẽ giới thiệu p
mọi dòng cho đến khi nó gặp điểm đánh dấu bắt đầu - khi nó q
hoàn toàn nhập vào. Công -u
tắc nbuffered là cần thiết cho GNU sed
vì nó có thể đệm khá khác, nhưng - theo thông số kỹ thuật - các POSIX khác sed
sẽ hoạt động mà không cần xem xét đặc biệt - miễn <infile
là một tệp thông thường.
Khi sed
q
uits đầu tiên , shell thực thi do
khối của vòng lặp - gọi một khối khác sed
in mọi dòng cho đến khi nó gặp dấu hiệu kết thúc . Nó dẫn đầu ra của nó tới paste
, bởi vì nó in số dòng trên mỗi dòng riêng của chúng. Như thế này:
1
line M
2
line N
3
line O
paste
sau đó dán những thứ đó lại với nhau trên các :
ký tự và toàn bộ đầu ra trông như sau:
line A
line B
1:line X
2:line Y
3:line Z
line C
line D
1:line M
2:line N
3:line O
Đây chỉ là ví dụ - mọi thứ có thể được thực hiện trong cả thử nghiệm hoặc thực hiện các khối ở đây, nhưng tiện ích đầu tiên không được tiêu thụ quá nhiều đầu vào.
Tất cả các tiện ích liên quan đều đọc cùng một đầu vào - và in kết quả của chúng - mỗi lượt trong lượt của chúng. Kiểu này mà có thể khó khăn để nhận được hang của - vì tiện ích khác nhau sẽ đệm hơn những người khác - nhưng bạn thường có thể dựa vào dd
, head
và sed
để làm điều đúng (mặc dù, cho GNU sed
, bạn cần cli-switch) và bạn phải luôn luôn có thể dựa vào read
- bởi vì về bản chất, nó rất chậm . Và đó là lý do tại sao vòng lặp trên chỉ gọi nó một lần cho mỗi khối đầu vào.
nl
không phải tích lũy trạng thái . Nhìn vàonl -d
và kiểm traman
/info
trang của bạn để biết thông tin về dấu phân cáchnl
của phần .