Thay thế một chuỗi dài bằng lệnh sed: Danh sách đối số lỗi quá dài


7

Tôi đang cố gắng thực hiện lệnh này

sed -i -e "s/BASE_64/$BASE_64/" FILE_NAME

trong đó $BASE_64một đại diện 64 cơ sở của một nội dung tập tin.

sed cho tôi một lỗi vì chuỗi quá dài.

Danh sách đối số quá dài

Làm thế nào có thể tránh được lỗi này?

Câu trả lời:


5

Đầu tiên, lưu dữ liệu được mã hóa base64 trong một tệp có tên, ví dụ : base64.txt.

Ví dụ:

base64 < originalfile > base64.txt

Sau đó:

printf '%s\n' '/BASE64/r base64.txt' 1 '/BASE64/d' w | ed FILENAME

Điều này sử dụng edđể tìm kiếm FILENAMEmột dòng chứa chuỗi BASE64, chèn nội dung của base64.txtsau dòng đó, quay lại dòng đầu tiên, sau đó tìm kiếm lại dòng có chuỗi BASE64và xóa nó. Các wchỉ huy edlưu các tập tin sửa đổi.


Điều gì xảy ra nếu BASE64chỉ là một phần của dòng và bạn không muốn thay thế toàn bộ dòng?
Eric Renouf

văn bản base64 có xu hướng là nhiều dòng ( nhiều dòng), vì vậy việc chèn nó vào giữa một dòng là loại vô nghĩa. Tôi sẽ /BASE64/r base64.txtchèn như trên, và sau đó s/BASE64//hơn là /BASE64/d.
cas

Đó có thể là, mặc dù một ví dụ ngắn trong đó nó sẽ phá vỡ dữ liệu được mã hóa trên dòng tiếp theo là nếu bạn đang điền tiêu đề Ủy quyền cho một yêu cầu HTTP bằng xác thực Cơ bản, thì bạn sẽ có một chuỗi mã hóa cơ sở ngắn 64. được thay thế tại chỗ, mặc dù có vấn đề trong tay, đó có lẽ không phải là tình huống trong trường hợp này
Eric Renouf

Trong trường hợp như vậy, a) sẽ cực kỳ khó xảy ra "Danh sách đối số lỗi quá dài" như OP đã báo cáo và b) Tôi sẽ sử dụng một phương pháp phù hợp hơn với nhiệm vụ trong tay ... một cách đơn giản s/BASE_64/$BASE_64_TEXT/với sed hoặc ed hoặc perl hoặc bất cứ điều gì có thể sẽ đủ.
cas

5

Bạn luôn có thể làm (vì bạn đã sử dụng GNU sedrồi ( -i)):

sed -i -f - FILE_NAME << EOF
s/BASE_64/$BASE_64/g
EOF

-f -nói sedđể đọc kịch bản sed từ stdin.

Nếu bạn muốn sử dụng lại kịch bản tương tự cho một số tập tin, trên Linux (và chỉ Linux), với một vỏ như bash, zsh, kshmà cụ ở đây các tài liệu với các tập tin tạm thời (như trái ngược với ống như dashhoặc yash) và vẫn với GNU sed, bạn có thể làm:

find . -name '*.conf' -exec sed -i -f /dev/stdin {} + << EOF
s/BASE_64/$BASE_64/g
EOF

Trên Linux (và chỉ Linux), /dev/stdinkhông có nghĩa là stdin theo cùng một cách -. Thay vào đó, nó là một liên kết tượng trưng đến tệp được mở trên stdin, vì vậy mỗi lần sedmở tệp, nó sẽ mở tệp lại từ đầu. Lệnh trên sẽ hoạt động tốt trên các hệ thống khác (có /dev/stdin) hoặc với hệ vỏ thực hiện ở đây - tài liệu có đường ống nhưng chỉ khi có ít conftệp đủ sedđược gọi một lần. Khi được gọi lần thứ hai, trên các hệ thống không phải Linux, như với -f -, /dev/stdinsẽ xuất hiện trống rỗng vì nó đã được đọc bởi lệnh gọi đầu tiên.

busybox sedcũng hỗ trợ -itheo cách tương tự như GNU sed, nhưng không hỗ trợ -f -. Vì vậy, bạn muốn sử dụng -f /dev/stdinở đó trong mọi trường hợp. Với FreeBSD sed, sử dụng:

sed -i '' -f /dev/stdin FILE_NAME << EOF
s/BASE_64/$BASE_64/g
EOF

4

Một lựa chọn khác sẽ được thay thế sedvới edvà lưu trữ các lệnh của bạn trong một tập tin. Ví dụ: nếu bạn tạo ed_cmdsvới các nội dung sau:

%s/BASE_64/<expanded variable>/g
w
q

sau đó bạn có thể chạy

< ed_cmds ed FILE_NAME

và nó sẽ thực hiện các thay đổi bạn muốn, vì vậy thay vì cài đặt, $BASE_64bạn sẽ tạo tệp lệnh ed.

Ed Giải thích

  • % có nghĩa là áp dụng lệnh cho từng dòng của tệp
  • s/pat1/pat2/gsự thay thế xuất hiện của pat1với pat2gcuối cùng làm cho nó làm điều đó cho mọi trận đấu trên đường, không chỉ lần đầu tiên
  • w ghi các thay đổi vào đĩa
  • q thoát (điều này sẽ xảy ra khi nó có EOF)

Tất nhiên, bạn cũng có thể đặt các sedlệnh của mình vào một tệp và sử dụng -f, nhưng nếu bạn đang làm điều đó và bạn muốn sửa đổi tệp tại chỗ, bạn cũng có thể sử dụng edthay vì tạo một tệp tạm thời và di chuyển nó như sed -ivậy.


bạn có thể vui lòng cho tôi ví dụ về giải pháp trên Tôi đang gặp vấn đề tương tự khi sử dụng sed. Tôi mới sử dụng shell không biết cách tạo tệp ed_cmds
springbootlearner

2

Kích thước của biểu diễn Base64 của tệp ($ BASE_64) quá dài và vượt quá kích thước đối số tối đa. Bạn sẽ có thể thấy giới hạn này cho hệ thống của mình bằng cách chạy

getconf ARG_MAX

Bạn phải tăng kích thước của ARG_MAXgiá trị. Nhưng tôi nghĩ nếu tập tin quá lớn, thì bạn sẽ phải sử dụng một cách tiếp cận khác để thực hiện việc thay thế này. Nếu một kịch bản Python sẽ làm điều đó cho bạn, tôi cũng sẽ thử nó với nó.


cảm ơn. Tôi sẽ đi với một kịch bản Python nếu không có giải pháp nào khác.
Lorenzo B

Lưu ý rằng Linux nói riêng có một giới hạn cứng mã hóa cho chiều dài của một đơn đối số dòng lệnh, do đó tăng ARG_MAXkhông thực hiện thậm chí giúp đỡ đó.
ilkkachu

2

Tôi đã kết thúc việc đưa các sedhướng dẫn vào một tập tin

SEDCOMMANDS=`tempfile`

và được gọi

sed -f "$SEDCOMMANDS" -- "$FILE_NAME"

Điều đó tốt nếu bạn không sử dụng sed -i. Nếu bạn muốn chỉnh sửa tệp tại chỗ, hãy làm theo https://unix.stackexchange.com/a/284188/149867 và đặt các edhướng dẫn tương đương trong một tệp, theo sau wq.


-ihoạt động tốt với -f. Chỉ, đảm bảo bạn sử dụng -i -f(hoặc -i '' -fvới BSD sed), không -if. Bạn cũng có thể sử dụng-f - để tránh các tập tin tạm thời.
Stéphane Chazelas
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.