'\ n' trong `IFS = $ '\ n' là một biến?


12

Tôi nhận thấy rằng để thiết lập dòng mới IFS phải có tiền tố $ làm tiền tố

IFS=$'\n'

nhưng nếu đặt dấu hai chấm, chỉ cần

IFS=:

\nmột biến?

Câu trả lời:


21

Đó là $'...'trong bashkhông phải là tham số mở rộng, đó là một loại đặc biệt của trích dẫn được giới thiệu bởi ksh93đó mở rộng những \n, \x0a, \12mã một ký tự xuống dòng. zshcũng được thêm vào \u000a. ksh93bashcũng có \cjtrong khi zsh\C-J. ksh93cũng hỗ trợ các biến thể như\x{a} .

Đây $là một gợi ý rằng nó là một hình thức hoặc mở rộng. Nhưng trong mọi trường hợp, nó khác với các hình thức mở rộng khác sử dụng $(như $((1 + 1)), $paramhoặc $(cmd)) ở chỗ nó không được thực hiện bên trong dấu ngoặc kép hoặc tài liệu ở đây ( echo "$'x'"đầu ra $'x'trong tất cả các vỏ mặc dù không được chỉ định trên POSIX) và việc mở rộng của nó không bị chia tách + toàn cầu, nó chắc chắn gần với một toán tử trích dẫn hơn một toán tử mở rộng.

IFS=\nsẽ đặt IFS thành n( \được coi là toán tử trích dẫn) và IFS="\n"hoặc IFS='\n'sẽ đặt IFS thành dấu gạch chéo ngược hai ký tự và n.

Bạn cũng có thể dùng:

IFS='
'

hoặc là

IFS="
"

hoặc là

IFS=$'
'

Để vượt qua một dòng mới theo nghĩa đen, mặc dù điều đó ít dễ đọc hơn (và người ta không thể nhìn thấy ngoài việc sử dụng những thứ như set listtrong viliệu$IFS có chứa các ký tự khoảng cách khác trong mã đó hay không).

IFS=:, IFS=':', IFS=":", IFS=$':'Tất cả các bộ IFS cho :nên nó không quan trọng mà bạn sử dụng.

$'...'được hỗ trợ (với các biến thể) bởi ít nhất: ksh93, zsh, bash, mksh, busybox sh, FreeBSD sh. ksh93bashcũng có một $"..."dạng trích dẫn được sử dụng để bản địa hóa văn bản mặc dù nó hiếm khi được sử dụng vì nó cồng kềnh để triển khai và sử dụng một cách hợp lý và đáng tin cậy.

Các shell esfishshell cũng có thể sử dụng \nbên ngoài dấu ngoặc kép để mở rộng sang dòng mới.

Một số công cụ như printf, một số triển khai echohoặc awkcũng có thể tự mở rộng \nchúng. Chẳng hạn, người ta có thể làm:

printf '\n'
awk 'BEGIN{printf "\n"}'
echo
echo '\n\c' # UNIX compliant echos only

để xuất ký tự dòng mới, nhưng lưu ý rằng:

IFS = $ (printf '\ n')

sẽ không hoạt động vì lệnh thay thế ( $(...)) loại bỏ tất cả các ký tự dòng mới. Tuy nhiên, bạn có thể sử dụng:

eval "$(printf 'IFS="\n"')"

Mà hoạt động vì đầu ra của printfkết thúc trong một "ký tự, không phải là một dòng mới.

Bây giờ, để hoàn chỉnh, trong rcshell và các dẫn xuất (như eshoặc akanga), $'\n'thực sự là sự mở rộng của \nbiến đó (một biến có tên là chuỗi gồm hai ký tự \n). Các shell đó không có giới hạn về tên biến ký tự có thể chứa và chỉ có một loại dấu ngoặc kép : '...'.

$ rc
; '\n' = (foo bar)
; echo $'\n'
foo bar
; echo $'\n'(1)
foo

rctất cả các biến cũng được xuất sang môi trường, nhưng ít nhất là trong biến thể Unix của rc, đối với các tên biến như \n, phiên bản biến môi trường trải qua một dạng mã hóa:

; env | grep foo | sed -n l
__5cn=foo\001bar$

( 0x5clà giá trị byte của ASCII \; xem thêm cách biến mảng đó được mã hóa với byte 0x1 làm dấu phân cách).


1
+1cho trình độ hiểu biết vô nhân đạo thông thường
Steven Penny

10

Đây là trích dẫn ANSI-C :

Từ ngữ của hình thức $'string'được đối xử đặc biệt. Từ này mở rộng thành string, với các ký tự thoát dấu gạch chéo ngược được thay thế theo quy định của tiêu chuẩn ANSI C.

Do đó $'\n'được thay thế bằng một dòng mới.

Điều này không liên quan đến việc mở rộng tham số shell , mặc dù sử dụng $.


6

Các chuỗi như $'\n'đã được giới thiệu bởi ksh93và hiện không phải là một phần của tiêu chuẩn POSIX.

Chúng cho phép sử dụng hầu hết các lối thoát C giống nhau, ví dụ $'\u2345'và các lối thoát cũng được hỗ trợ bởi echo.

Lưu ý rằng nếu bạn không thích (trong trường hợp ksh93 hoặc bash) sử dụng phương thức thoát đó, bạn vẫn có thể sử dụng:

IFS='
'

tương đương nhưng khó đọc hơn.

BTW: Tiện ích mở rộng này đã vượt qua tiêu chuẩn POSIX, nhưng nó được lên kế hoạch cho SUSv8 dự kiến ​​sẽ không xuất hiện trước năm 2020 vì trước tiên chúng tôi cần xử lý độ trễ của chúng tôi sau danh sách lỗi hiện tại.


Các $'...'mở rộng khác nhau từ đó echo. Chúng giống như những đối số cho đối số định dạng của printf. Đối với echo, 0 là bắt buộc trong \0123khi cho $'...'printfđịnh dạng, \0123sẽ là \012một dòng mới theo sau bởi một lứa 3.
Stéphane Chazelas

1
Lưu ý rằng các $'...'đặc điểm kỹ thuật vẫn đang được thảo luận. Có một số vấn đề vẫn phải giải quyết với từ ngữ hiện đang đề xuất.
Stéphane Chazelas

IIRC, Nó đã bị đóng cửa nhưng đã được mở lại. Do thực tế là vẫn còn nhiều thời gian trước khi nó có hiệu lực, tôi không thấy vấn đề thực sự với điều đó.
schily

1
Nó đã bị đóng cửa, tôi đưa ra một số phản đối, nó đã được mở lại, sau đó nó đã được sửa đổi, vẫn còn một số vấn đề (hầu hết là về \uxxxxviệc mở rộng) và không có giải pháp nào phù hợp với việc triển khai hiện có. Vì vậy, nó có thể không được đưa vào phiên bản POSIX tiếp theo. Có lẽ họ có thể để lại bản \uxxxxmở rộng cho vấn đề8, vì vậy chúng tôi vẫn có thể có ít nhất $'\n'.
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.