Giải thích cần thiết về cách tôi có thể lặp lại một ký tự trong shell POSIX


8

Câu trả lời sau đây về Stack Overflow,

Làm thế nào tôi có thể lặp lại một nhân vật trong bash?

áp đặt một cách hợp lý của POSIX - lặp lại một ký tự duy nhất, như sau. Trong ví dụ này, hãy sử dụng dấu bằng 100 lần:

printf %100s | tr " " "="

Vấn đề của tôi là tôi không hiểu cách thức hoạt động của nó và tôi muốn một lời giải thích đơn giản. Xin vui lòng kiềm chế các ý kiến ​​như đọc hướng dẫn , tôi đã làm như vậy, và vì tôi không thông minh từ nó, tôi đang hỏi câu hỏi này vì tôi chưa bao giờ sử dụng tr, cũng không thấy một printftuyên bố như vậy .

Câu trả lời:


13

Nói tóm lại, printf %100ssẽ in 100 dấu cách và tr " " "="sẽ chuyển đổi các khoảng trắng đó thành các dấu bằng nhau, in hiệu quả 100 dấu bằng.

Phá vỡ nó:


printflà một vỏ tích hợp. Nó thường có hai hoặc nhiều đối số, trong đó đối số đầu tiên là "chuỗi định dạng" và phần còn lại sẽ được sử dụng để điền vào chỗ dành sẵn trong chuỗi định dạng đó. Khi mẫu đó được điền đầy đủ, nó sẽ in ra kết quả. Nếu có nhiều đối số còn lại, nó sẽ bắt đầu lại, điền vào nhiều đối số hơn và in chuỗi kết quả.

Chuỗi định dạng được sử dụng để printflấy thông số kỹ thuật định dạng, bắt đầu bằng %và kết thúc bằng một chữ cái, %dcó nghĩa là một số nguyên (sử dụng cơ sở thập phân, do đó "d"), %fcó nghĩa là số dấu phẩy động và %scó nghĩa là một chuỗi ký tự. Các ký tự không phải là chữ cái sau các %từ bổ nghĩa cho đặc tả định dạng và đặc biệt, các số được sử dụng để chỉ định độ dài yêu cầu của trường trên đầu ra. Vì vậy, %100ssẽ định dạng chuỗi có ít nhất 100 ký tự, nó sẽ đệm chuỗi đó bằng dấu cách và nó sẽ giữ cho chuỗi được căn chỉnh đúng (nói cách khác, thêm khoảng trắng ở đầu chuỗi.)

Nếu thông qua một đối số phụ, nó sẽ sử dụng nó cho %strường đó , vì vậy, ví dụ printf %100s abcsẽ in 97 khoảng trắng (để có tổng số 100, xem xét 3 trong "abc") theo sau là chuỗi "abc" thực tế. Nhưng nếu không có đối số nào được đưa ra, thì đặc tả định dạng được điền bằng một đối số rỗng hoặc null (là một chuỗi trống cho %s, nó sẽ là 0 cho %d, v.v.) Vì vậy, điều đó giống như khi một chuỗi trống được thông qua, chẳng hạn như printf %100s ''. Kết quả cuối cùng là chỉ có phần đệm 100 ký tự được in.

Vì vậy, đặt tất cả lại với nhau, printf %100skết quả trong 100 không gian được in.


Bây giờ trlà một công cụ để dịch các ký tự từ đầu vào sang đầu ra. Phải mất hai đối số, SET1 và SET2, mỗi bộ một ký tự và sau đó dịch ký tự đầu tiên của SET1 thành ký tự đầu tiên của SET2, ký tự thứ hai của SET1 thành thứ hai của SET2, v.v. trđọc đầu vào của nó từ stdin và ghi lại vào stdout (vì vậy nó rất hữu ích trong các đường ống như ở trên.) trsẽ luôn dịch tất cả các lần xuất hiện của ký tự đó trong một chuỗi đã cho.

Ví dụ, tr aeiou 12345sẽ dịch nguyên âm chữ thường thành các số từ 1 đến 5 theo thứ tự đó, vì vậy nó sẽ dịch "xếp hàng" thành "q52523ng" chẳng hạn. Bạn cũng có thể chuyển phạm vi ký tự của nó, chẳng hạn như tr a-z A-Zđể biến bất kỳ chữ cái viết thường nào thành chữ hoa tương ứng.

Vì vậy, tr " " "="chỉ đơn giản là dịch các không gian thành các dấu bằng trong suốt chuỗi. Không gian đầu tiên cần được trích dẫn để được công nhận là một đối số. Các =không thực sự cần phải được trích dẫn, nhưng làm như vậy không bị tổn thương. tr " " =sẽ làm việc như vậy.


Đặt tất cả lại với nhau, in 100 khoảng trắng, sau đó dịch từng khoảng đó thành các dấu bằng nhau.

Hy vọng rằng điều này giải thích nó đủ chi tiết, nhưng nếu vẫn còn điều gì đó bạn không hiểu, vui lòng để lại nhận xét và tôi sẽ cố gắng giải quyết vấn đề đó.


Chỉ cần kiểm tra, liệu những điều sau đây có chính xác hơn về mặt cú pháp không?:printf '%100s' ' ' | tr " " "="
LinuxSecurityFreak

2
@Vlastimil Trên thực tế printf '%100s' '', với một chuỗi trống ... Tôi đã cập nhật câu trả lời để bao gồm điều đó. Trong trường hợp cụ thể này, chuỗi trống hoặc một khoảng trắng sẽ không tạo ra sự khác biệt, nhưng bạn có thể thấy một sự khác biệt trong printf '%sx\n'đó, giống như printf '%sx\n' ''nhưng khác với printf '%sx\n' ' '. Tôi hy vọng điều đó sẽ giúp!
filbranden

1
+1 để đề cập rằng trhoạt động trên các bộ ký tự. Điều này thường bị bỏ lại.
Sergiy Kolodyazhnyy

11

Các printflệnh sử dụng đối số đầu tiên của nó như một định dạng để in luận tiếp theo của nó. printf %100sin ra các đối số của nó được đệm tới 100 ký tự, sử dụng khoảng trắng (ở bên trái). Không có đối số được cung cấp để định dạng, do đó, nó định dạng chuỗi trống một lần và xuất ra 100 khoảng trắng. Bạn có thể thấy rằng:

$ printf %100s | hexdump -C
00000000  20 20 20 20 20 20 20 20  20 20 20 20 20 20 20 20  |                |
*
00000064

(20 là hex cho một khoảng trắng, *có nghĩa là dòng trước đó được lặp lại)

Các chuỗi định dạng sử dụng khoảng các Xprintfchỉ định C : %, chiều rộng tùy chọn để khớp với giá trị được định dạng và loại định dạng sẽ sử dụng. slà định dạng chuỗi và các chuỗi được đệm bằng khoảng trắng ở bên trái theo mặc định. Có thể có nhiều định dạng hoặc các phần nghĩa đen khác: printf "a%10sb\n" hellobản in

 a         xb.

trthay thế các ký tự được chọn trong đầu vào tiêu chuẩn của nó bằng các thay thế đã chọn và in kết quả ra đầu ra tiêu chuẩn của nó. tr " " "="có một ký tự duy nhất được thay thế - một khoảng trắng - và một ký tự đơn để thay thế nó bằng - một dấu bằng. Do đó, nó biến mọi không gian trong đầu vào của nó thành một =và không thay đổi phần còn lại. Bạn cũng có thể thử điều đó:

$ tr " " "="
hello world
hello=world

(Tôi đã gõ "thế giới xin chào")

Bạn có thể có nhiều thay thế: tr abc defbiến a thành d, b thành e, c thành f và giữ phần còn lại không thay đổi. Đây chỉ là một nhân vật duy nhất, vì đó là thứ printfcó thể tạo ra với giá rẻ.

Đường ống |làm cho đầu ra của lệnh ở bên trái, printf %100sđược sử dụng làm đầu vào cho lệnh ở bên phải , tr " " "=". Đó là, một trăm không gian liên tiếp được đưa ra trvà mỗi một trong số chúng được thay thế bằng một =, với chuỗi mới được in ra.

printf %100s | tr " " "="
====================================================================================================

Chỉ cần kiểm tra, liệu những điều sau đây có chính xác hơn về mặt cú pháp không?:printf '%100s' ' ' | tr " " "="
LinuxSecurityFreak

1
Định dạng một không gian và đệm nó với các khoảng trắng sẽ cho cùng một đầu ra như định dạng một chuỗi rỗng và đệm với các khoảng trắng, nhưng nó không tương đương về mặt cấu trúc. Có lẽ nó "chính xác" hơn về mặt rõ ràng về những gì đang diễn ra, nhưng không phải về mặt cú pháp, và chúng là các lệnh khác nhau.
Michael Homer
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.