Để lưu một mô tả tập tin, bạn nhân đôi nó trên một fd khác. Lưu một đường dẫn đến tệp tương ứng là không đủ, bạn cần lưu chế độ mở, cờ mở, vị trí hiện tại trong tệp, v.v. Và tất nhiên, đối với các đường ống ẩn danh hoặc ổ cắm, điều đó sẽ không hoạt động vì những đường ống này không có đường dẫn. Những gì bạn muốn lưu là mô tả tệp mở mà fd đề cập đến và sao chép một fd thực sự trả về một fd mới cho cùng một mô tả tệp mở .
Để sao chép một bộ mô tả tệp lên một cái khác, với shell giống như Bourne, cú pháp là:
exec 3>&1
Ở trên, fd 1 được nhân đôi lên fd 3.
Bất cứ điều gì fd 3 đã được mở trước đó sẽ bị đóng, nhưng lưu ý rằng fds 3 đến 9 (thường là nhiều hơn, lên tới 99 với yash
) được dành riêng cho mục đích đó (và không có ý nghĩa đặc biệt trái với 0, 1 hoặc 2), Shell biết không sử dụng chúng cho kinh doanh nội bộ của riêng mình. Lý do duy nhất fd 3 sẽ được mở trước đó là vì bạn đã thực hiện nó trong kịch bản 1 hoặc nó đã bị rò rỉ bởi người gọi.
Sau đó, bạn có thể thay đổi thiết bị xuất chuẩn sang thứ khác:
exec > /dev/null
Và sau đó, để khôi phục thiết bị xuất chuẩn:
exec >&3 3>&-
( 3>&-
để đóng bộ mô tả tập tin mà chúng ta không còn cần nữa).
Bây giờ, vấn đề với điều đó là ngoại trừ trong ksh, mọi lệnh bạn chạy sau đó exec 3>&1
sẽ thừa hưởng fd 3. Đó là một rò rỉ fd. Nói chung không phải là một vấn đề lớn, nhưng điều đó có thể gây ra vấn đề.
ksh
đặt cờ close-on-exec trên các fds đó (đối với fds trên 2), nhưng không phải các shell khác và các shell khác không có cách nào để đặt cờ đó theo cách thủ công.
Công việc xung quanh cho shell khác là đóng fd 3 cho mỗi và mọi lệnh, như:
exec 3>&-
exec > file.log
ls 3>&-
uname 3>&-
exec >&3 3>&-
Cồng kềnh. Ở đây, cách tốt nhất là không sử dụng exec
, mà chuyển hướng các nhóm lệnh:
{
ls
uname
} > file.log
Ở đó, lớp vỏ cần chú ý để lưu thiết bị xuất chuẩn và khôi phục nó sau đó (và nó thực hiện nó bên trong bằng cách sao chép nó trên một fd (trên 9, trên 99 đối với yash
) với bộ cờ close-on-exec ).
Lưu ý 1
Bây giờ, việc quản lý các fds 3 đến 9 đó có thể trở nên cồng kềnh và có vấn đề nếu bạn sử dụng chúng rộng rãi hoặc trong các chức năng, đặc biệt nếu tập lệnh của bạn sử dụng một số mã bên thứ ba có thể lần lượt sử dụng các fds đó.
Một số vỏ ( zsh
, bash
, ksh93
, tất cả các bổ sung tính năng ( được đề xuất bởi Oliver người hay nói đùa củazsh
) trong khoảng thời gian tương tự vào năm 2005 sau khi nó đã được thảo luận giữa các nhà phát triển của họ) có một cú pháp thay thế cho giao fd miễn phí đầu tiên trên 10 thay vì giúp trong trường hợp này:
myfunction() {
local fd
exec {fd}>&1
# stdout was duplicated onto a new fd above 10, whose actual value
# is stored in the fd variable
...
# it should even be safe to re-enter the function here
...
exec >&"$fd" {fd}>&-
}