Ý nghĩa chính xác của IFS = $ '\ n' là gì?


124

Nếu ví dụ sau, đặt IFSbiến môi trường thành ký tự nguồn cấp dữ liệu dòng ...

IFS=$'\n'
  • Không những gì ký hiệu đô la có nghĩa là chính xác ?
  • Nó làm gì trong trường hợp cụ thể này?
  • Tôi có thể đọc thêm ở đâu về cách sử dụng cụ thể này (Google không cho phép các ký tự đặc biệt trong tìm kiếm và tôi không biết phải tìm kiếm gì khác)?

Tôi biết IFSbiến môi trường là gì và \nký tự là gì (nguồn cấp dữ liệu dòng), nhưng tại sao không sử dụng biểu mẫu sau: IFS="\n"(không hoạt động)?

Ví dụ: nếu tôi muốn lặp qua mọi dòng của tệp và muốn sử dụng vòng lặp for, tôi có thể làm như sau:

for line in (< /path/to/file); do
    echo "Line: $line"
done

Tuy nhiên, điều này sẽ không hoạt động trừ khi IFSđược đặt thành ký tự nguồn cấp dữ liệu dòng. Để làm cho nó hoạt động, tôi phải làm điều này:

OLDIFS=$IFS
IFS=$'\n'
for line in (< /path/to/file); do
    echo "Line: $line"
done
IFS=$OLDIFS

Lưu ý: Tôi không cần một cách khác để làm điều tương tự, tôi đã biết nhiều cách khác rồi ... Tôi chỉ tò mò về điều đó $'\n'và tự hỏi liệu có ai có thể cho tôi lời giải thích về nó không.

Câu trả lời:


161

Thông thường bashkhông giải thích trình tự thoát trong chuỗi ký tự. Vì vậy, nếu bạn viết \nhoặc "\n"hoặc '\n', đó không phải là dấu ngắt dòng - đó là chữ cái n(trong trường hợp đầu tiên) hoặc dấu gạch chéo ngược theo sau là chữ cái n(trong hai trường hợp còn lại).

$'somestring'là một cú pháp cho các ký tự chuỗi với các chuỗi thoát . Vì vậy, không giống như '\n', $'\n'thực sự là một linebreak.


2
Không hẳn như vậy - \nchỉ là một chữ cái (thoát ra) n. Bạn đúng đó '\n'"\n"bị phản ứng dữ dội theo sau là n.
Roman Cheplyaka

15
Lưu ý rằng điều đó $'\n'là dành riêng cho bash - nó sẽ không hoạt động trong trình bao POSIX ( /bin/sh). Để có được tác dụng tương tự một cách POSIX-compliant, bạn có thể gõ IFS=', sau đó ấn Enter để gõ một ký tự xuống dòng thực tế, sau đó gõ bế mạc'
Richard Hansen

23
IFS=$(echo -e '\n')cũng nên làm điều đó theo cách tương thích với POSIX.
Vineet

12
@Vineet - nó đã khiến tôi phải tạm dừng tranh chấp một nhận xét được ủng hộ. Mặc dù điều này đúng Posix, nhưng nó không hoạt động - Các toán tử thay thế lệnh trong bash loại bỏ tất cả các ký tự dòng mới ở cuối. Xem điều này để biết thêm chi tiết .
Digital Trauma

9
@DigitalTrauma Tôi nghĩ nó thậm chí không phải là POSIX: -ekhông được định nghĩa và \nkhông -ehoạt động như một phần mở rộng XSI: pubs.opengroup.org/onlinepubs/9699919799/utilities/… . printf '\n'đá;)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

20

Chỉ để đặt tên chính thức cho cấu trúc : các chuỗi có dạng $'...'được gọi là chuỗi được trích dẫn C ANSI .

Nghĩa là, như trong chuỗi [ANSI] C, chuỗi thoát phản ứng dữ dội được nhận dạng và mở rộng thành tương đương theo nghĩa đen của chúng (xem bên dưới để biết danh sách đầy đủ các chuỗi thoát được hỗ trợ).

Sau khi mở rộng này, các $'...'chuỗi hoạt động giống như các '...'chuỗi - tức là, chúng được coi là các ký tự KHÔNG phải tuân theo bất kỳ mở rộng shell [thêm] nào .

Ví dụ, $'\n'mở rộng đến một ký tự xuống dòng đen - đó là một cái gì đó một chuỗi bash đen thường xuyên (dù là '...'hay "...") không thể làm. [1]

Một tính năng thú vị khác là các chuỗi được trích dẫn C trong ANSI có thể thoát '(dấu ngoặc kép)\' , mà '...'(các chuỗi được trích dẫn đơn thông thường) không thể:

echo $'Honey, I\'m home' # OK; this cannot be done with '...'

Danh sách các chuỗi thoát được hỗ trợ :

Các chuỗi thoát dấu gạch chéo ngược, nếu có, được giải mã như sau:

\ a alert (chuông)

\ b backspace

\ e \ E một ký tự thoát (không phải ANSI C)

\ f form feed

\ n dòng mới

\ r xuống dòng

\ t tab ngang

\ v tab dọc

\ gạch chéo ngược

\ 'một câu trích dẫn

\ "dấu ngoặc kép

\ nnn ký tự tám bit có giá trị là giá trị bát phân nnn (một đến ba chữ số)

\ xHH ký tự tám bit có giá trị là giá trị thập lục phân HH (một hoặc hai chữ số hex)

\ uHHHH ký tự Unicode (ISO / IEC 10646) có giá trị là giá trị thập lục phân HHHH (một đến bốn chữ số hex)

\ UHHHHHHHH ký tự Unicode (ISO / IEC 10646) có giá trị là giá trị thập lục phân HHHHHHHH (một đến tám chữ số hex)

\ cx một ký tự control-x

Kết quả mở rộng được trích dẫn một lần, như thể ký hiệu đô la không có mặt.


[1] Tuy nhiên, bạn có thể nhúng các dòng mới thực vào các chuỗi '...' và "..."; tức là, bạn có thể xác định các chuỗi kéo dài nhiều dòng.


16

Từ http://www.linuxtopia.org/online_books/bash_guide_for_beginners/sect_03_03.html :

Các từ ở dạng "$ 'STRING'" được xử lý theo một cách đặc biệt. Từ mở rộng thành một chuỗi, với các ký tự thoát ra sau dấu gạch chéo ngược được thay thế như được chỉ định bởi tiêu chuẩn ANSI-C. Trình tự thoát dấu gạch chéo ngược có thể được tìm thấy trong tài liệu Bash. Tìm thấy

Tôi đoán nó đang buộc tập lệnh thoát khỏi nguồn cấp dữ liệu dòng theo tiêu chuẩn ANSI-C thích hợp.


8

Khôi phục IFS mặc định - điều này OLDIFS=$IFSlà không cần thiết. Chạy IFS mới trong vỏ con để tránh ghi đè IFS mặc định:

ar=(123 321); ( IFS=$'\n'; echo ${ar[*]} )

Ngoài ra, tôi không thực sự tin rằng bạn khôi phục IFS cũ đầy đủ. Bạn nên trích dẫn gấp đôi nó để tránh ngắt dòng chẳng hạn OLDIFS="$IFS".


2
đây là một kỹ thuật thực sự hữu ích. tôi vừa sử dụng nó cho một trình tham gia trình bao sạch hơn op : args=$(IFS='&'; echo "$*"). khôi phục IFSđến $' \t\n'một cách thân thiện Bourne shell là một kỳ công không có ý nghĩa.
jeberle

Re Besides I don't really believe you recover the old IFS fully: word splitting không được thực hiện trên RHS của các phép gán biến (nhưng loại bỏ trích dẫn thì được thực hiện), vì vậy OLDIFS=$IFSOLDIFS="$IFS"hoạt động theo cùng một cách.
mklement0

3

Các chuỗi được trích dẫn trong ANSI C là một điểm chính. Cảm ơn @ mklement0.

Bạn có thể kiểm tra các chuỗi được trích dẫn C ANSI bằng lệnh od.

echo -n $'\n' | od -c
echo -n '\n' | od -c
echo -n $"\n" | od -c
echo -n "\n" | od -c

Kết quả đầu ra:

0000000  \n  
0000001

0000000   \   n   
0000002

0000000   \   n   
0000002

0000000   \   n   
0000002

Bạn có thể biết ý nghĩa rõ ràng bằng các kết quả đầu ra.


-7

Nó giống như lấy giá trị từ một biến:

VAR='test'
echo VAR
echo $VAR

khác nhau, vì vậy về cơ bản ký hiệu đô la đánh giá nội dung.


6
Điều này không liên quan gì đến các biến. $'FOO'(không giống như $FOOcâu hỏi này không phải về) là một chuỗi ký tự. Nếu bạn thực thi echo $'VAR', bạn sẽ thấy rằng nó in chuỗi VARchứ không phải test.
sepp2k
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.