Câu hỏi Làm thế nào để sử dụng sudo để chuyển hướng đầu ra đến một vị trí mà tôi không có quyền ghi vào?


Tôi đã được cho sudo truy cập vào một trong các hộp Linux RedHat phát triển của chúng tôi, và tôi dường như tìm thấy bản thân mình khá thường xuyên cần phải chuyển hướng đầu ra đến một vị trí tôi không bình thường có quyền ghi vào.

Vấn đề là, ví dụ giả tạo này không hoạt động:

sudo ls -hal /root/ > /root/test.out

Tôi chỉ nhận được phản hồi:

-bash: /root/test.out: Permission denied

Làm cách nào tôi có thể làm việc này?


699
2017-09-17 11:44


gốc


sử dụng chmod u + w filename - Szabolcs Dombi
@ DombiSzabolcs Bạn đang gợi ý rằng tôi tạo tệp như sudo trước, sau đó cho phép bản thân mình? Ý tưởng tốt. - Jonathan


Các câu trả lời:


Lệnh của bạn không hoạt động vì chuyển hướng được thực hiện bởi trình bao của bạn mà không có quyền ghi vào /root/test.out. Chuyển hướng đầu ra không phải là được thực hiện bởi sudo.

Có nhiều giải pháp:

  • Chạy một trình bao với sudo và cung cấp lệnh cho nó bằng cách sử dụng -c Tùy chọn:

    sudo sh -c 'ls -hal /root/ > /root/test.out'
    
  • Tạo một kịch bản lệnh bằng lệnh của bạn và chạy tập lệnh đó bằng sudo:

    #!/bin/sh
    ls -hal /root/ > /root/test.out
    

    Chạy sudo ls.sh. Xem Steve Bennett's câu trả lời nếu bạn không muốn tạo tệp tạm thời.

  • Khởi chạy trình bao với sudo -s sau đó chạy lệnh của bạn:

    [nobody@so]$ sudo -s
    [root@so]# ls -hal /root/ > /root/test.out
    [root@so]# ^D
    [nobody@so]$
    
  • Sử dụng sudo tee (nếu bạn phải trốn thoát rất nhiều khi sử dụng -c Tùy chọn):

    sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null
    

    Chuyển hướng đến /dev/null là cần thiết để dừng lại tee từ xuất ra màn hình. Đến nối thêm thay vì ghi đè tệp đầu ra (>>), sử dụng tee -a hoặc là tee --append (tùy chọn cuối cùng dành riêng cho GNU coreutils).

Cảm ơn đi Jd, Adam J. Forster và Johnathan cho các giải pháp thứ hai, thứ ba và thứ tư.


976
2017-09-17 11:48



Có một câu trả lời tuyệt vời cho bạn biết cách chuyển hướng STDERR và STDOUT riêng biệt tại đây: stackoverflow.com/questions/692000/… ... về cơ bản perl -e 'print "STDIN\n"; print STDERR "STDERR\n"; ' > >( tee stdout.log ) 2> >( tee stderr.log >&2 ) - errant.info
Bạn sẽ muốn thực hiện 'sudo -E ...' để sử dụng các biến trong lệnh shelled out (ví dụ, khi sử dụng các biến này trong một kịch bản lệnh). - Urhixidur
Việc chuyển hướng đầu ra của tee sang / dev / null có thể không cần thiết trong nhiều trường hợp, việc lặp lại đầu ra màn hình là vô hại. Ví dụ, khi giao dịch chỉ với đầu ra của lệnh thông thường hoặc nội dung của các tập tin văn bản nhỏ. - thomasrutter


Một người nào đó ở đây vừa gợi ý sudoing tee:

sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null

Điều này cũng có thể được sử dụng để chuyển hướng bất kỳ lệnh nào, đến một thư mục mà bạn không có quyền truy cập. Nó hoạt động vì chương trình tee thực sự là chương trình "echo to a file", và chuyển hướng tới / dev / null là dừng nó cũng xuất ra màn hình để giữ nó giống như ví dụ ban đầu ở trên.


80
2017-09-17 12:26



Trong nhiều trường hợp, cụ thể là nếu người dùng bình thường có lời mời thực hiện lệnh và "chỉ" không thể ghi vào tệp đầu ra mong muốn, thì đầu tiên sudo (ví dụ: đối với lệnh) có thể bị bỏ qua - Hagen von Eitzen


Một mẹo tôi đã tự tìm ra là

sudo ls -hal /root/ | sudo dd of=/root/test.out

65
2017-11-21 14:24



sudo dd là tốt hơn so với sudo tee /root/file > /dev/null ví dụ ở trên! - kristianlm
dd không phải là một lệnh tối nghĩa lạ. Nó được sử dụng bất cứ khi nào bạn cần sao chép một lượng lớn dữ liệu với bộ đệm giữa hai thiết bị khối. Cú pháp thực sự khá đơn giản, dd là tên lệnh, of=/root/test.out là đối số cho biết dd những tập tin đầu ra là gì. - rhlee
@steve Tất cả mọi thứ là 'tối nghĩa' cho đến khi bạn tìm hiểu nó là gì. of có nghĩa tập tin đầu ra và dd là một công cụ rất phổ biến được sử dụng trong cả Linux và OSX (chủ yếu để ghi hình ảnh vào đĩa). Đây là một thủ thuật gọn gàng chắc chắn. - blockloop
dd có thể hữu ích bằng nhau tee đây. Trong cả hai trường hợp, bạn đang sử dụng một lệnh phổ biến, nổi tiếng với mục đích, trong khi hơi khác với mục đích dự định ban đầu của nó, vẫn còn được biết đến và được ghi chép đầy đủ. Trong khi dd là tốt sao chép một lượng lớn dữ liệu, nó không hút với một lượng nhỏ. Nó có lợi ích ở đây là không lặp lại đầu ra cho đầu ra tiêu chuẩn. - thomasrutter
Bất cứ khi nào bạn gõ từ sudo dd bên cạnh nhau, bạn muốn làm rất, rất chắc chắn rằng các đối số theo sau là chính xác (đặc biệt là xem xét cú pháp không chuẩn của nó). Họ không gọi nó là "tàu khu trục" vì không có gì ... - ali_m


Vấn đề là ở chỗ chỉ huy được chạy dưới sudo, nhưng sự chuyển hướng được chạy dưới người dùng của bạn. Điều này được thực hiện bởi vỏ và có rất ít bạn có thể làm gì về nó.

sudo command > /some/file.log
`-----v-----'`-------v-------'
   command       redirection

Cách thông thường của việc bỏ qua điều này là:

  • Quấn các lệnh trong một kịch bản mà bạn gọi dưới sudo.

    Nếu lệnh và / hoặc tệp nhật ký thay đổi, bạn có thể thực hiện kịch bản lấy chúng làm đối số. Ví dụ:

    sudo log_script command /log/file.txt
    
  • Gọi một trình bao và truyền dòng lệnh dưới dạng tham số -c

    Điều này đặc biệt hữu ích cho một lệnh tắt phức hợp. Ví dụ:

    sudo bash -c "{ command1 arg; command2 arg; } > /log/file.txt"
    

38
2017-09-23 10:10





Tuy nhiên, một biến thể khác về chủ đề:

sudo bash <<EOF
ls -hal /root/ > /root/test.out
EOF

Hoặc tất nhiên:

echo 'ls -hal /root/ > /root/test.out' | sudo bash

Họ có lợi thế (nhỏ) mà bạn không cần phải nhớ bất kỳ đối số nào sudo hoặc là sh/bash


18
2018-05-13 03:53





Làm cho sudo chạy một shell, như sau:

sudo sh -c "echo foo > ~root/out"

15
2017-09-17 11:48





Làm rõ một chút về lý do tại sao lựa chọn tee thích hợp hơn

Giả sử bạn có quyền thích hợp để thực thi lệnh tạo đầu ra, nếu bạn đặt đầu ra của lệnh của bạn thành tee, bạn chỉ cần nâng cao quyền sở hữu của tee bằng sudo và tee trực tiếp để viết (hoặc nối thêm) vào tệp được đề cập.

trong ví dụ được đưa ra trong câu hỏi có nghĩa là:

ls -hal /root/ | sudo tee /root/test.out

cho một vài ví dụ thực tế hơn:

# kill off one source of annoying advertisements
echo 127.0.0.1 ad.doubleclick.net | sudo tee -a /etc/hosts

# configure eth4 to come up on boot, set IP and netmask (centos 6.4)
echo -e "ONBOOT=\"YES\"\nIPADDR=10.42.84.168\nPREFIX=24" | sudo tee -a /etc/sysconfig/network-scripts/ifcfg-eth4

Trong mỗi ví dụ này, bạn đang lấy đầu ra của một lệnh không có đặc quyền và ghi vào một tệp thường chỉ có thể ghi bởi gốc, đó là nguồn gốc của câu hỏi của bạn.

Bạn nên làm theo cách này vì lệnh tạo đầu ra không được thực hiện với các đặc quyền nâng cao. Nó không có vẻ quan trọng ở đây với echo nhưng khi lệnh nguồn là một kịch bản mà bạn không hoàn toàn tin tưởng, nó là rất quan trọng.

Lưu ý bạn có thể sử dụng tùy chọn -a để đánh dấu để nối thêm (như >>) vào tệp đích thay vì ghi đè lên nó (như >).


15
2017-11-02 01:51



Xin lỗi js3, nhưng điều này đã được đề xuất (vào năm 2008) và đang ngồi ở câu trả lời cao thứ hai: stackoverflow.com/a/82553/6910 - Jonathan
Bạn nói đúng, Jonathan, tôi sẽ cập nhật câu trả lời của tôi để mở rộng về những lý do tại sao đây là một lựa chọn thích hợp hơn. Cảm ơn bạn đã phản hồi hữu ích. - jg3


Làm thế nào về viết một kịch bản?

Tên tệp: myscript

#!/bin/sh

/bin/ls -lah /root > /root/test.out

# end script

Sau đó sử dụng sudo để chạy tập lệnh:

sudo ./myscript

5
2017-09-17 11:48





Cách tôi sẽ đi về vấn đề này là:

Nếu bạn cần viết / thay thế tệp:

echo "some text" | sudo tee /path/to/file

Nếu bạn cần phải nối thêm vào tệp:

echo "some text" | sudo tee -a /path/to/file

5
2018-06-24 19:48



Điều này khác biệt như thế nào với các câu trả lời ở trên? - Jonathan


Tôi sẽ làm theo cách này:

sudo su -c 'ls -hal /root/ > /root/test.out'

4
2018-04-21 12:33



Điều đó thực sự có vẻ sạch hơn một chút, vì bạn không cần phải xác định rõ ràng trình bao. - Steve Bennett
Một nhược điểm nhỏ là nó chạy một quá trình bổ sung (su): $ sudo su -c 'pstree -sp $$ >/dev/fd/1'  init(1)───gnome-terminal(6880)───bash(6945)───sudo(401)───su(402)───bash(410)───pstree(411) - pabouk