Làm cách nào để in các chuỗi được phân tách bằng TAB trong bash?


9

Tôi đang cố gắng in hai chuỗi được phân tách bằng TAB. Tôi đã thử:

echo -e 'foo\tbar'
printf '%s\t%s\n' foo bar

Cả hai đều in:

foo     bar

Trong đó khoảng trắng giữa hai thực tế là 5 khoảng trắng (theo lựa chọn đầu ra bằng chuột trong Putty).

Tôi cũng đã thử sử dụng CTRL + V và nhấn TAB khi gõ lệnh, với kết quả tương tự.

Cách chính xác để buộc tab được in dưới dạng tab, vì vậy tôi có thể chọn đầu ra và sao chép nó sang một nơi khác, với các tab?

Và câu hỏi phụ: tại sao bash mở rộng các tab vào không gian?

Cập nhật : Rõ ràng, đây là sự cố của Putty: /superuser/656838/how-to-make-putty-display-tabs-within-a-file-instead-of-changing-them-to không gian



Tại sao không thoát khỏi nó? printf '%s\\t%s\n' foo bar
Valentin Bajrami

@steel ấn Cảm ơn điều đó rất giống với những gì tôi cần, nhưng cuối cùng không có giải pháp nào ...
Asu

1
@Valentin Kết quả đó foo\tbar...
wjandrea 16/12/18

1
Mặc dù thực tế rằng bạn đã biết rằng bạn có một vấn đề với thiết bị đầu cuối của mình: Bash tự nó diễn giải $'\t'như là trình lập bảng. Vì vậy, bạn luôn có thể nối các chuỗi như thế này - ví dụ như gán: v='This is'$'\t''a test'Và in nó theo nghĩa đen, ví dụprintf '%s' "$v"
rexkogitans 17/12/18

Câu trả lời:


9

Giống như ilkkachu đã nói, đây không phải là vấn đề với bash, nhưng với trình giả lập thiết bị đầu cuối chuyển đổi các tab thành khoảng trắng trên đầu ra.

Kiểm tra các thiết bị đầu cuối khác nhau, putty, xterm và konsole chuyển đổi các tab thành không gian, trong khi urxvt và gnome-terminal thì không. Vì vậy, một giải pháp khác là chuyển đổi thiết bị đầu cuối.


3
Nó cũng có thể được thực hiện bởi trình điều khiển tty sau khi bạn chạy stty tab3.
Stéphane Chazelas

14

khoảng trắng giữa hai thực tế là 5 khoảng trắng.

Không, không phải vậy. Không có trong đầu ra của echohoặc printf.

$ echo -e 'foo\tbar' | od -c
0000000   f   o   o  \t   b   a   r  \n
0000010

Cách chính xác để buộc tab được in dưới dạng tab, vì vậy tôi có thể chọn đầu ra và sao chép nó sang một nơi khác, với các tab?

Đây là một vấn đề khác nhau. Nó không phải là về shell mà là trình giả lập thiết bị đầu cuối, giúp chuyển đổi các tab thành khoảng trắng trên đầu ra. Nhiều, nhưng không phải tất cả trong số họ làm điều đó.

Có thể dễ dàng hơn để chuyển hướng đầu ra với các tab vào một tệp và sao chép nó từ đó hoặc sử dụng unexpandtrên đầu ra để chuyển đổi khoảng trắng thành các tab. (Mặc dù nó cũng không thể biết các khoảng trắng bắt đầu bằng các tab nào và sẽ chuyển đổi tất cả các tab đó thành các tab, nếu có thể.) Điều này tất nhiên sẽ phụ thuộc vào chính xác những gì bạn cần làm với đầu ra.


Tôi có nghĩa là khi tôi cố gắng chọn đầu ra, nó được coi là 5 khoảng trắng. Cảm ơn 'od -c' để xác minh nội dung của đầu ra lệnh.
Asu

1
@Asu Tôi nghĩ anh ấy hiểu điều đó. Giải pháp của anh là lấy đầu ra thông qua các phương tiện khác vì trình giả lập thiết bị đầu cuối không được đảm bảo để lại các tab dưới dạng các tab khi bạn chọn chúng trong cửa sổ. Tuy nhiên, tôi chỉ kiểm tra và trong khi putty, xterm và konsole chuyển đổi các tab thành khoảng trắng, urxvt và gnome-terminal thì không. Vì vậy, một giải pháp khác là chuyển đổi thiết bị đầu cuối.
JoL

@JoL Vâng, đó là kết luận tôi mới đưa ra một phút trước, và tôi nghĩ đó sẽ là câu trả lời được chấp nhận nếu ai đó quan tâm đăng nó như vậy ...
Asu

1
@Asu, yeah, tôi nghĩ về việc giải quyết vấn đề bằng tay. Sẽ rất khó chịu khi phải làm điều đó, nhưng sau đó tôi thừa nhận tôi đã nhận ra rằng có những trình giả lập thiết bị đầu cuối hỗ trợ sao chép các tab. Thay đổi thành một trong đó, tất nhiên sẽ là một giải pháp tốt hơn nhiều!
ilkkachu

4

Trong printf '%s\t%s\n' foo bar, printfkhông đầu ra foo<TAB>bar<LF>.

f, o, b, arlà nhân vật đồ họa đơn chiều rộng.

Khi nhận được các ký tự đó, thiết bị đầu cuối sẽ hiển thị glyph tương ứng và di chuyển con trỏ một cột sang phải, trừ khi nó đã chạm tới cạnh phải của màn hình (giấy trong máy đánh chữ gốc), trong trường hợp đó, nó có thể cung cấp một dòng và trở về cạnh trái của màn hình (bọc) hoặc chỉ loại bỏ ký tự tùy thuộc vào thiết bị đầu cuối và cách nó được cấu hình.

<Tab><LF>là hai nhân vật điều khiển . <LF>(còn gọi là dòng mới) là dấu phân cách dòng trong văn bản Unix, nhưng đối với thiết bị đầu cuối, nó chỉ cung cấp một dòng (di chuyển con trỏ xuống một vị trí). Vì vậy, trình điều khiển đầu cuối trong kernel sẽ thực sự dịch nó sang <CR>(quay lại cạnh trái của màn hình), <LF>(con trỏ xuống) ( stty onlcrthường được bật theo mặc định).

<Tab> yêu cầu thiết bị đầu cuối di chuyển con trỏ đến điểm dừng tab tiếp theo (mà trên hầu hết các thiết bị đầu cuối cách nhau 8 vị trí nhưng cũng có thể được cấu hình để được đặt ở bất cứ đâu) mà không lấp đầy khoảng trống bằng khoảng trống.

Vì vậy, nếu các ký tự đó được gửi đến một thiết bị đầu cuối có tab dừng mỗi 8 cột trong khi con trỏ ở đầu một dòng trống, điều đó sẽ dẫn đến:

foo     bar

in trên màn hình ở dòng đó. Nếu chúng được gửi trong khi con trỏ ở vị trí thứ ba trong một dòng có chứa xxxxyyyyzzzz, điều đó sẽ dẫn đến:

xxfooyyybarz

Trên các thiết bị đầu cuối không hỗ trợ lập bảng, trình điều khiển thiết bị đầu cuối có thể được cấu hình để dịch các tab đó thành chuỗi các khoảng trắng. ( stty tab3).

Ký tự SPC, trong máy đánh chữ điện thoại gốc sẽ di chuyển con trỏ sang phải, trong khi backspace ( \b) sẽ di chuyển nó sang bên trái. Bây giờ trong các thiết bị đầu cuối hiện đại, SPC di chuyển sang phải và cũng xóa (viết một ký tự không gian như bạn mong đợi). Vì vậy, mặt dây chuyền \bphải là một cái gì đó mới hơn ASCII. Trên hầu hết các thiết bị đầu cuối hiện đại, nó thực sự là một chuỗi các ký tự: <Esc>, [, C.

Có nhiều chuỗi thoát để di chuyển nnhân vật sang trái, phải, lên, xuống hoặc tại bất kỳ vị trí nào trên màn hình. Có các chuỗi thoát khác để xóa (điền vào chỗ trống) các phần của dòng hoặc vùng trên màn hình, v.v.

Những chuỗi thường được sử dụng bởi các ứng dụng hình ảnh như vi, lynx, mutt, dialognơi văn bản được viết ở vị trí tùy ý trên màn hình.

Bây giờ, tất cả các trình giả lập thiết bị đầu cuối X11 và một vài trình giả lập không phải X11 khác như GNU screencho phép bạn chọn các khu vực trên màn hình để sao chép dán. Khi bạn chọn một phần của những gì bạn thấy trong vitrình chỉnh sửa, bạn không muốn sao chép tất cả các chuỗi thoát đã được sử dụng để tạo đầu ra đó. Bạn muốn chọn văn bản bạn nhìn thấy ở đó.

Ví dụ: nếu bạn chạy:

printf 'abC\rAC\bB\t\e[C\b\bD\n'

Mô phỏng phiên soạn thảo nơi bạn nhập abC, quay lại từ đầu, thay thế abbằng AC, Cbằng B, di chuyển đến điểm dừng tab tiếp theo, sau đó thêm một cột ở bên phải, sau đó hai cột ở bên trái, sau đó nhập D.

Bạn thấy:

ABC    D

Đó là, ABCmột khoảng cách 4 cột và D.

Nếu bạn chọn bằng chuột trong xtermhoặc putty, chúng sẽ lưu trữ trong vùng chọn ABC, 4 ký tự khoảng trắng và D, không abC<CR>AC<BS>B<Tab><Esc>[C<BS><BS>D.

Những gì kết thúc trong lựa chọn là những gì đã được gửi printfnhưng được xử lý sau bởi cả trình điều khiển đầu cuối và trình giả lập thiết bị đầu cuối.

Đối với các loại chuyển đổi khác, hãy xem <U+0065><U+0301>( etheo sau là một dấu cấp tính kết hợp) được thay đổi thành <U+00E9>( édạng được soạn sẵn) bởi xterm.

Hoặc echo abcrằng đầu lên được dịch sang ABCbằng lái xe thiết bị đầu cuối trước khi gửi đến nhà ga sau một stty olcuc.

Bây giờ, <Tab>giống như <LF>một trong số ít các ký tự điều khiển đôi khi thực sự được tìm thấy trong các tệp văn bản (cũng <CR>trong các tệp văn bản MSDOS và đôi khi <FF>để ngắt trang).

Vì vậy, một số trình giả lập thiết bị đầu cuối chọn sao chép chúng khi có thể trong bộ đệm sao chép-dán để bảo quản chúng (thường không phải là trường hợp <CR>cũng như <LF>vậy).

Ví dụ, trong các thiết bị đầu cuối dựa trên VTE gnome-terminal, bạn có thể thấy rằng, khi bạn chọn đầu ra của printf 'a\tb\n'một dòng trống, gnome-terminalthực sự lưu trữ a\tbtrong lựa chọn X11 thay vì a7 khoảng trắng và b.

Nhưng đối với đầu ra của printf 'a\t\bb\n', nó cửa hàng a, 6 không gian và b, và cho printf 'a\r\tb\n', a, 7 chỗ và b.

Có những trường hợp khác mà các thiết bị đầu cuối sẽ cố gắng sao chép đầu vào thực tế, như khi bạn chọn hai dòng sau khi chạy printf 'a \nb\n'nơi không gian dấu vết vô hình đó sẽ được bảo tồn. Hoặc khi chọn hai dòng không bao gồm ký tự LF khi hai dòng kết quả từ việc bọc ở lề phải.

Bây giờ, nếu bạn muốn lưu trữ đầu ra của printfvào CLIPBOARD X11, tốt nhất là thực hiện trực tiếp như sau:

printf 'foo\tbar\n' | xclip -sel c

Lưu ý rằng khi bạn dán nó vào xtermhoặc hầu hết các thiết bị đầu cuối khác, xtermthực tế sẽ thay thế \nbằng \rvì đó là ký tự xtermgửi khi bạn nhấn Enter(và trình điều khiển thiết bị đầu cuối có thể dịch lại \n).


Điều này là rất sâu sắc, cảm ơn bạn. Tôi đã thử giải pháp xclip và nó hoạt động. Nhưng nó không làm chính xác những gì tôi nghĩ và yêu cầu X11. Có thể điều này sẽ có ích vào một lúc nào đó, cảm ơn!
Asu

@Asu, X11là những gì xử lý lựa chọn sao chép-dán trong trình giả lập thiết bị đầu cuối như xtermhoặc puttytrên Unix. Các trình giả lập thiết bị đầu cuối khác có thể có cơ chế sao chép-dán và cách lưu trữ nội dung tùy ý trong đó, như các lệnh readbufregistertrong màn hình GNU.
Stéphane Chazelas 17/12/18
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.