Chuyển hướng thiết bị xuất chuẩn sang tệp bạn không có quyền ghi


113

Khi bạn cố gắng sửa đổi một tệp mà không có quyền ghi trên đó, bạn sẽ gặp lỗi:

> touch /tmp/foo && sudo chown root /tmp/foo
> echo test > /tmp/foo
zsh: permission denied: /tmp/foo

Sudaging không giúp ích gì, vì nó chạy lệnh dưới quyền root, nhưng shell xử lý chuyển hướng xuất chuẩn và mở tệp như bạn bằng mọi cách:

> sudo echo test > /tmp/foo
zsh: permission denied: /tmp/foo

Có cách nào dễ dàng để chuyển hướng thiết bị xuất chuẩn sang tệp mà bạn không có quyền ghi vào, ngoài việc mở một vỏ như root và thao tác với tệp theo cách đó?

> sudo su
# echo test > /tmp/foo

2
Trả lời cho một câu hỏi tương tự từ StackOverflow stackoverflow.com/questions/82256/ory
Cristian Ciupitu

Làm thế nào bạn có thể không có quyền đối với một tập tin bạn tự tạo trong tmp? nó có phải là của umask không?
k961

@ k961 Tôi đã sử dụng chownđể thay đổi chủ sở hữu; đó chỉ là một ví dụ
Michael Mrozek

Câu trả lời:


116

Có, sử dụng tee. Vì vậy, echo test > /tmp/footrở thành

echo test | sudo tee /tmp/foo

Bạn cũng có thể chắp thêm ( >>)

echo test | sudo tee -a /tmp/foo

27
Tee cũng sẽ xuất ra thiết bị xuất chuẩn; đôi khi bạn không muốn nội dung lấp đầy màn hình. Để khắc phục điều này, hãy làmecho test | sudo tee /tmp/foo > /dev/null
Shawn J. Goff

Làm thế nào bạn sẽ làm điều đó với heredoc?
JohnDoea

26

Để thay thế nội dung của tệp bằng đầu ra của echo(như >toán tử chuyển hướng shell).

echo test | sudo dd of=/tmp/foo

Để ghi vào tệp (lúc đầu, mặc dù bạn có thể sử dụng seekđể xuất ở các độ lệch khác nhau) mà không cần cắt bớt (như 1<>toán tử shell Bourne):

echo test | sudo dd of=/tmp/foo conv=notrunc

Để thêm vào tệp (như >>), với GNU dd:

echo test | sudo dd of=/tmp/foo oflag=append conv=notrunc

Xem thêm GNU dd's conv=exclđể tránh clobbering một tập tin hiện có (như với set -o noclobbertrong vỏ POSIX) và conv=nocreatcho điều ngược lại (chỉ cập nhật một tập tin hiện có).


tài giỏi! điều này làm giảm bớt sự cần thiết phải echo test | sudo tee /tmp/foo >/dev/nullloại bỏ đầu ra.
Adam Katz

2
Tôi có thể phải lấy lại điều đó; ddlà không đáng tin cậy cho điều đó trừ khi bạn đang sử dụng các tùy chọn chỉ dành cho GNU tối nghĩa iflag=fullblock oflag=fullblock, loại bỏ tính thanh lịch của câu trả lời này. Tôi sẽ gắn bó với tee.
Adam Katz

5
dd đáng tin cậy với bs không tối nghĩa = 1
umeboshi

2
@umeboshi Nhưng chỉ đáng tin cậy nếu bạn đủ kinh nghiệm để biết chính xác những gì bạn đang làm. For ddcó thể khá nguy hiểm (nếu không nói: tàn phá) nếu chỉ một lỗi nhỏ được thực hiện. Vì vậy, đối với người dùng mới, tôi muốn giới thiệu teephương pháp này là trên bờ an toàn.
cú pháp

1
@AdamKatz, trong trường hợp dd of=filemột mình (không có count/ skip...), nó đáng tin cậy. iflag=fullblocklà không cần thiết bởi vì ở đây ddghi vào đầu ra những gì nó đã đọc trên đầu vào. Nó không quan trọng nếu nó không phải là khối đầy đủ.
Stéphane Chazelas

12

tee có lẽ là sự lựa chọn tốt nhất, nhưng tùy thuộc vào tình huống của bạn, một cái gì đó như thế này có thể là đủ:

sudo sh -c 'echo test > /tmp/foo'

1
3 vấn đề: evalthay vì đơn giản sh -c; -i, sẽ thay đổi thư mục làm việc của bạn; chạy toàn bộ lệnh dưới dạng root, có thể thay đổi hành vi của nó hoặc có thể gây ra rủi ro không cần thiết. Tại sao điều này bao giờ có được một upvote?

4
bạn đã không, nhưng nó gây hiểu lầm, nói chung là xấu và thậm chí có thể nguy hiểm.

5

Mặc dù tôi đồng ý, đó | sudo teelà cách chính tắc, đôi khi sed (ở đây giả sử GNU sed) có thể hoạt động:

cat sudotest 
line 1

sudo sed -i '1iitest' sudotest && cat sudotest 
itest
line 1

sudo sed -i '$aatest' sudotest && cat sudotest 
itest
line 1
atest

-isửa đổi các tập tin tại chỗ. 1icó nghĩa là chèn trước dòng 1. $acó nghĩa là nối sau dòng cuối cùng.

Hoặc sao chép vào xclipboard:

somecommand | xclip
sudo gedit sudotest
move cursor to desired place, click middle mouse button to insert, save

1
Đây là từ giống như một câu đố Trung Quốc cổ đại. Không thể nhìn thấy để hiểu làm thế nào điều này có rất nhiều upvote. ( hrmph )
cú pháp

1
@syntaxerror: Thưa ông, tôi xin lỗi, tôi không phải là người nói tiếng Anh bản ngữ. Nếu bạn chỉ định những gì không rõ ràng với bạn, tôi có thể cố gắng cải thiện câu trả lời của mình. So với 65 upvote cho Gert, 4 dường như không phải là nhiều upvote, bạn nghĩ sao?
người dùng không xác định

Chà, tôi sẽ khá hài lòng với 4 :-D Tiếng Anh của bạn không tệ chút nào. Nó chỉ được nói trong một loại nerdspeak terse techie. Tôi phải đoán bạn là một lập trình viên. Các lập trình viên lẫn nhau sẽ hiểu chính họ một cách hoàn hảo theo cách đó, nhưng một người không phải là lập trình viên phải nghĩ rằng nó được diễn đạt giống như ... như đã nói.
cú pháp

Lưu ý rằng sed -ikhông thực sự sửa đổi tệp tại chỗ - nó tạo một tệp tạm thời và đổi tên tệp khi thoát. Vì vậy, bạn sẽ không thể làm một cái gì đó giống như tail -f ...trên tệp gốc và xem đầu ra sử dụng sed -i ...trong khi đường ống đang chạy
Andrew Henle

@AndrewHenle: Có, vì kích thước có thể tăng hoặc thu hẹp và vì đó có thể là trường hợp đối với hầu hết các yêu cầu sed, và bạn thậm chí không thể - afaik - ghi vào cùng một vị trí trên SSD, nó chỉ hoạt động giả 'tại chỗ' . Là một người nói tiếng Anh không phải là người bản ngữ, tôi có thể yêu cầu một biểu thức ngắn gọn, không có khả năng giải thích sai? Chỉ -i creates a new file of same namehoặc có một cái gì đó nhỏ gọn hơn? Tôi đoán tôi thích in place, bởi vì nó giải thích i. Trang web gnu-sed cũng gọi nó tại chỗ và cờ dài là --in-place.
người dùng không xác định

2

Tôi đã đá xung quanh ý tưởng của mình cho một vấn đề tương tự, và đưa ra các giải pháp sau:

  • sudo uncattrong đó uncatmột chương trình đọc đầu vào tiêu chuẩn và ghi nó vào tệp có tên trên dòng lệnh, nhưng tôi chưa viết uncat.

  • sudocatbiến thể của sudoeditđiều đó tôi chưa viết mà làm sạch hơn sudo cathay sudo uncat.

  • hoặc mẹo nhỏ này khi sử dụng sudoeditvới EDITOR là tập lệnh shell

    #!/bin/sh
    # uncat
    cat > "$1"

    có thể được gọi là một trong hai |sudo ./uncat filehoặc | EDITOR=./uncat sudoeditnhưng có tác dụng phụ thú vị.


catlấy một danh sách các tập tin để con mèo inate, do đó, nên lấy một danh sách các tập tin để un con mèo inate. Nó sẽ phải sử dụng phép thuật để quyết định số lượng cần đặt trong mỗi tệp. Tên thay thế bao gồm dog, to-file, redirect.
ctrl-alt-delor

Tôi không thể nghĩ ra bất kỳ lý do tại sao tôi muốn uncatkhi tôi có tee.
tự đại diện

1
Chà, teecó một nhược điểm nhỏ là nó viết stdin của nó vào thiết bị xuất chuẩn của nó - được giảm nhẹ bằng cách chuyển hướng thiết bị xuất chuẩn sang /dev/null. Các lựa chọn thay thế khác bao gồm dd of=/tmp/foo(được đề cập trong câu trả lời khác), trong đó ghi thông tin trạng thái vào stderr, và cp /dev/stdin /tmp/foo.
Scott

1

Sử dụng bọt biển từ gói moreutils. Nó có lợi thế là nó không ghi vào thiết bị xuất chuẩn.

echo test | sudo sponge /tmp/foo

Sử dụng tùy chọn -a để thêm vào một tệp thay vì ghi đè lên nó.


1
Tôi không chắc chắn lợi thế gì khi không viết lên các bản trình bày xuất sắc, nhưng bạn chỉ có thể chuyển hướng đầu ra sang /dev/nullnếu đó là một vấn đề
Michael Mrozek

1
Tất nhiên tôi có thể chuyển hướng đến / dev / null, nhưng lệnh dễ đọc và gõ hơn mà không cần chuyển hướng. Ưu điểm của việc không viết lên thiết bị xuất chuẩn là thiết bị đầu cuối của tôi không chứa đầy rác.
Hontvári Levente

1
Tôi sẽ không cài đặt một gói để dự phòng chuyển hướng, nhưng tôi thường xuyên sử dụng bọt biển, vì vậy nó đã ở đó.
Hontvári Levente

0

Lỗi xuất phát từ thứ tự mà shell thực hiện.

Việc chuyển hướng được xử lý trước khi trình bao thậm chí thực thi sudovà do đó được thực hiện với sự cho phép của người dùng mà bạn hiện đang làm việc. Vì bạn không có quyền ghi để tạo / cắt bớt mục tiêu của chuyển hướng, bạn sẽ permission deniedgặp lỗi từ trình bao.

Giải pháp là đảm bảo rằng tệp đầu ra được tạo dưới danh tính được cung cấp cho bạn bởi sudo, ví dụ tee:

$ generate_output | sudo tee target_file
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.