Chèn văn bản từ tệp nội tuyến sau khi khớp mẫu trong tệp khác


8

Tôi đang cố lấy nội dung của một tệp và chèn nó sau một mẫu phù hợp trong một tệp khác bằng sed. Câu hỏi của tôi rất giống với câu hỏi này , nhưng tôi muốn chèn nội dung của một tệp nội tuyến hơn là trên một dòng mới. Tôi có thể làm cái này như thế nào?

Sử dụng câu hỏi ví dụ mà tôi đã tham chiếu, câu trả lời đầu tiên thực hiện chính xác những gì tôi muốn; tuy nhiên, tôi muốn chèn vào nội tuyến:

sed '/First/r file1.txt' infile.txt 

Dữ liệu thực tế tôi muốn chèn là một tệp JSON:

[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
]

Tôi nghĩ rằng điều này trả lời câu hỏi của bạn. Bạn sẽ nhìn vào nó và cho tôi biết?
mikeerv

@mikeerv Cảm ơn sự giúp đỡ. Tôi rất vui khi thử giải pháp của bạn, nhưng sau khi đọc giải pháp của bạn, tôi không chắc làm thế nào để thực hiện những gì bạn đề xuất. Bạn có thể gửi một ví dụ?
rùa

Tôi chắc chắn đang xem xét nó - nó có vẻ đơn giản - nhưng tôi không biết bắt đầu từ đâu ... OOps. mô hình là First- duh. lấy làm tiếc.
mikeerv

Đợi đã - bạn muốn chèn dòng mới JSON miễn phí - như xóa dòng mới khỏi tệp được chèn khi nó được chèn? Tôi có thể làm điều đó với GNU sednhưng tôi chỉ muốn chắc chắn ...
mikeerv

JSON thực tế không cần phải thay đổi, tôi muốn chèn JSON sau mẫu để không có dòng mới giữa mẫu và bắt đầu JSON.
rùa

Câu trả lời:


6

Trong câu hỏi được liên kết của bạn đã có awkcâu trả lời tốt , chỉ cần sửa đổi một chút bằng cách sử dụng printfthay vì printchèn nội dung mà không có dòng mới:

awk '/First/ { printf $0; getline < "File1.txt" }1' infile.txt

Kết quả:

Some Text here
FirstThis is text to be inserted into the File.
Second
Some Text here

Bạn có thể muốn thêm không gian hoặc phân cách khác sau "Đầu tiên" với printf $0 " "; ...


Nếu tệp được chèn có nhiều dòng thì:

awk '/First/{printf $0; while(getline line<"File1.txt"){print line};next}1' infile.txt

Kết quả:

Some Text here
First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
]
Second
Some Text here

Trong trường hợp sử dụng thực tế của tôi, tôi đang chèn một tệp JSON lớn và ví dụ awk này không hoạt động. Tôi chỉ nhận được một nẹp trái duy nhất, [được chèn sau khi khớp mẫu. Văn bản bình thường hoạt động tốt, nhưng không phải JSON?
rùa

Đã thêm một tệp dữ liệu JSON mẫu không chèn chính xác cho tôi.
rùa

@turtle mà có lẽ vì getlineđọc trong một dòng. Sử dụng một vòng lặp xung quanh getline: unix.stackexchange.com/a/32911/70524
muru

Ok, nó đã hoạt động, nhưng JSON đang được chèn ngay TRƯỚC KHI mẫu bây giờ:awk '/First/ { while(getline line<"File1.txt"){print line} }1' infile.txt
rùa

@turtle thử awk '/First/ { print; while(getline line<"File1.txt"){print line} }' infile.txtthay.
muru

6

Bạn có thể sử dụng perl(lấy nội dung tệp và thay thế patternbằng pattern+ file content):

perl -pe '$text=`cat insert.txt`; chomp($text); s/PAT/$&$text/' file.txt

thêm -iđể chỉnh sửa tại chỗ; gđể nối thêm sau mỗi lần xuất hiện (mẫu), ví dụ:

perl -i -pe '$text=`cat insert.txt`; chomp($text); s/PAT/$&$text/g' file.txt

Một cách khác, sử dụng ed:

printf '%s\n' /PAT/s/PAT/\&\\ \/ - kb ". r insert.txt" j \'b j ,p q | ed -s file.txt

để chỉnh sửa tại chỗ, thay thế ,pbằng w:

 printf '%s\n' /PAT/s/PAT/\&\\ \/ - kb ". r insert.txt" j \'b j w q | ed -s file.txt

Có lẽ không ai quan tâm đến cách thức hoạt động của nó, nhưng dù sao, printfchuyển một danh sách các lệnh tới ed:

/PAT/s/PAT/&\             #   set address to first line matching PAT and
/                         #   split the line right after PAT
-                         #   set address one line before (return to the line matching PAT)
kb                        #   mark the current line
. r insert.txt            #   insert content of insert.txt after this line         
j                         #   join current line and the next
'b                        #   set  address to marked line (return to the line matching PAT)
j                         #   join current line and the next one
,p                        #   print file content
q                         #   quit editor

Hoặc, không sử dụng printf|:

ed -s file.txt <<< $'/PAT/s/PAT/&\\\n/\n-\nkb\n. r insert.txt\nj\n\'b\nj\nw\nq\n'

Tôi đã từng trải qua 8 giờ đồng hồ sâu trong các extài liệu - Tôi thực sự thích viđiều cửa sổ điều khiển bạn có thể làm. Một dòng duy nhất hoặc một kích thước có thể điều chỉnh hoặc ... tốt, rất nhiều thứ có lẽ, mà tôi không bao giờ hiểu được. Dù sao, tôi thực sự muốn tìm hiểu điều đó - tôi chỉ lướt qua các tài liệu POSIX. bạn có bất kì gợi ý nào không?
mikeerv

Không có nhiều tài nguyên (mà tôi biết, than ôi) bao gồm ed... các tài liệu POSIX, cũng có trang này ... Tôi khuyên bạn nên sử dụng công cụ cho các nhiệm vụ / thử nghiệm đơn giản (ít nhất, đó là cách tôi đã học, chỉ đọc docs, đoạn giới thiệu ngắn của Kernighan và tờ cheat của Krummins ). Với kiến ​​thức của bạn về sed, bạn sẽ không có vấn đề. Trừ khi câu hỏi của bạn là về ex(tôi không sử dụng exnhiều, nếu có) ...
don_crissti

nó là về ex- mà theo tôi hiểu, nó chỉ là một edphần mở rộng? một thứ đã ném tôi khi tôi chơi với nó là bộ lưu trữ tmp - tôi đã thử tải lên một tệp lớn và phải chờ nó. mặt khác, điều tôi thấy hấp dẫn ở đó là vô số bộ đệm - tôi chỉ không đủ tốt để tách chúng ra một cách hiệu quả. cảm ơn các liên kết
mikeerv

5

Vì vậy, sẽ có một chút khó khăn để làm cho công việc này trở nên rõ ràng sed- bạn nên tìm kiếm cutvà / hoặc pastevới một số tiền thân regex tạo tập lệnh của chúng trong ngữ cảnh đó - và điều này là vì sedsẽ luôn chèn một \newline trước đầu ra của read. Tuy nhiên, w / GNU sed:

sed '/First/{x;s/.*/cat file/e;H;x;s/\n//}' <<\IN 
First
Second
Third
IN

Điều đó hoạt động bằng cách ethực hiện catmỗi khi nó gặp /First/địa chỉ của bạn . Nó thực hiện điều này trong hkhông gian cũ (dù sao - một bộ đệm thay thế - bởi vì tôi xthay đổi chúng, nó thực sự xảy ra trong không gian mẫu đã từng là hkhông gian cũ) để bảo toàn nội dung của dòng khớp Firstvà sau đó nối thêm catđầu ra đến dòng của bạn và loại bỏ \newline can thiệp .

ĐẦU RA:

First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
]
Second
Third

Bây giờ nếu bạn muốn toàn bộ nội dung của tệp khớp giữa hai phần của một dòng phải hoạt động khác nhau một chút vì với lệnh trên, tôi chỉ cần xóa dòng mới giữa cuối dòng phù hợp và đầu tệp. Tuy nhiên, bạn cũng có thể làm điều này:

sed '/First/{s//&\n/;h
         s/.*/{ cat file; echo .; }/e;G
         s/\(.*\).\n\(.*\)\n/\2\1/
}' <<\IN
Third
Second
First Second Third
Third
Second
First Second Third
IN

Điều đó phân chia dòng tại trận đấu với một \nký tự ewline, lưu nó trong hkhông gian cũ, executes cat- thay thế không gian mẫu bằng đầu ra của nó - Glấy nội dung của không gian giữ được gắn vào không gian mẫu mới của chúng ta theo một \nký tự ewline khác , sau đó sắp xếp lại \nphân định ewline.

Tôi làm echo .để bảo vệ bất kỳ dấu \nký tự ewline trong file- nhưng nếu đó không phải là mong muốn của bạn (và không phải là rất phù hợp với ví dụ của bạn anyway) bạn có thể làm mà không có nó và loại bỏ đầu tiên .trước .\ntrong sau s///ubstitution.

Ngay trước khi sắp xếp lại không gian mô hình trông như thế này:

^cat's output - any number of newlines.*.\nmatch on First\nrest of match$

ĐẦU RA:

Third
Second
First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
] Second Third 
Third
Second
First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
] Second Third

1
Đó là một câu trả lời tuyệt vời Mike.
don_crissti

@don_crissti - cảm ơn rất nhiều. Các s///elà cú pháp là khá mát mẻ - bạn có thể làm bất cứ điều gì bạn với nó mà bạn có thể làm tại dấu nhắc. Trong thực tế, nó cũng làm cho một bộ xử lý nhanh chóng khá tiện dụng. Tôi đã thử nghiệm với nó và một số shell cơ bản hơn không cung cấp nhiều cách chỉnh sửa dòng và gây ấn tượng. Nếu bạn sử dụng nó, hãy nhớ lưu ý rằng bạn loại bỏ tất cả không gian mẫu khi bạn thực hiện - chỉ thay thế một phần dữ liệu tùy ý và sau đó ethực hiện các kết quả có thể là thảm họa. Tôi biết - tôi đã từng ở đó.
mikeerv
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.