Làm cách nào để sử dụng sudo để chuyển hướng đầu ra đến một vị trí mà tôi không được phép ghi vào?


881

Tôi đã được cấp quyền truy cập sudo trên 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ư thấy mình thường xuyên cần chuyển hướng đầu ra đến một vị trí mà tôi thường không có quyền truy cập ghi.

Vấn đề là, ví dụ giả định 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 thế nào tôi có thể làm điều này để làm việc?


1
sử dụng tên tệp chmod u + w
Szabolcs Dombi

@DombiSzabolcs Bạn đang đề nghị tôi tạo tệp dưới dạng sudo trước, sau đó cho phép bản thân mình? Ý tưởng tốt.
Jonathan

Trong nhiều tình huống bạn kết thúc ở đây vì bạn đã hỏi "tại sao tôi lại bị từ chối?" Đôi khi câu trả lời là bạn cần phải tạo một tệp như root(trong trường hợp đó tiến hành đọc câu trả lời) nhưng rất thường xuyên, bạn chỉ cần tạo tệp ở một nơi khác, như chính bạn.
tripleee

1
Sau khi vật lộn với những câu trả lời này, cuối cùng tôi chọn chuyển hướng đến một tệp tạm thời và sudo di chuyển nó đến đích.
TingQian LI

Câu trả lời:


1233

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

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

  • Chạy shell với sudo và đưa ra lệnh cho nó bằng cách sử dụng -ctùy chọn:

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

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

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

  • Khởi chạy một shell với sudo -ssau đó chạy các 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 thoát rất nhiều khi sử dụng -ctùy chọn):

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

    Việc chuyển hướng đến /dev/nulllà cần thiết để ngăn tee xuất ra màn hình. Để chắp thêm thay vì ghi đè tệp đầu ra ( >>), hãy sử dụng tee -ahoặc tee --append( tệp cuối cùng dành riêng cho GNU coreutils ).

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


1
Có một câu trả lời tuyệt vời cho bạn biết cách chuyển hướng riêng biệt STDERR và STDOUT tại đây: stackoverflow.com/questions/692000/ chủ ... về cơ bảnperl -e 'print "STDIN\n"; print STDERR "STDERR\n"; ' > >( tee stdout.log ) 2> >( tee stderr.log >&2 )
errant.info

2
Bạn sẽ muốn làm 'sudo -E ...' để sử dụng các biến trong lệnh bóc ra (ví dụ: khi sử dụng điều này trong một tập lệnh).
Urhixidur

3
Chuyển hướng đầu ra tee thành / dev / null có lẽ không cần thiết trong nhiều trường hợp trong đó việc lặp lại đầu ra ra màn hình là vô hại. Ví dụ: khi xử lý chỉ với đầu ra của các lệnh thông thường hoặc nội dung của các tệp văn bản nhỏ.
thomasrutter 7/07/2015

105

Ai đó ở đây vừa đề nghị 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à một chương trình "echo to a file" và chuyển hướng đến / dev / null là để ngăn chặn nó cũng xuất ra màn hình để giữ cho nó giống như ví dụ ban đầu được nêu ở trên.


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

81

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

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

16
sudo ddlà tốt hơn so với các sudo tee /root/file > /dev/nullví dụ trên!
kristianlm

14
dd không phải là một lệnh tối nghĩa kỳ 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, ddlà tên lệnh, of=/root/test.outlà đối số cho biết ddTệp đầu ra là gì.
rhlee

14
@steve Mọi thứ đều 'tối nghĩa' cho đến khi bạn tìm hiểu nó là gì. ofcó nghĩa là tệp đầu raddlà một công cụ rất phổ biến được sử dụng trong cả Linux và OSX (chủ yếu để ghi ảnh vào đĩa). Đây là một mẹo gọn gàng cho chắc chắn.
blockloop

12
ddcó lẽ cũng hữu ích như 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 cho một mục đích, mặc dù hơi khác với mục đích ban đầu của nó, vẫn nổi tiếng và được ghi chép rõ ràng. Mặc dù ddrất tốt trong việc sao chép lượng dữ liệu khổng lồ, nhưng nó không hút với số lượng nhỏ. Nó có lợi ích ở đây là không lặp lại đầu ra thành đầu ra tiêu chuẩn.
thomasrutter 7/07/2015

26
Bất cứ khi nào bạn gõ từ sudo ddbên cạnh nhau, bạn muốn thực hiện rất, rất chắc chắn rằng những lập luận rằng theo là chính xác (đặc biệt là xem xét cú pháp phi tiêu chuẩn của nó). Họ không gọi nó là "kẻ hủy đĩa" mà không có gì ...
ali_m

45

Vấn đề là lệnh được chạy bên dưới sudo, nhưng 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 về nó.

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

Những cách thông thường để bỏ qua điều này là:

  • Gói các lệnh trong một tập lệnh mà bạn gọi theo sudo.

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

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

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

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

23

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

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


18

Làm rõ một chút về lý do tại sao tùy chọn tee là 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 chuyển đầu ra của lệnh thành tee, bạn chỉ cần nâng cao quyền riêng tư của tee bằng sudo và tee trực tiếp để ghi (hoặc nối thêm) vào tệp đang đề 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 được bằng root, đó là nguồn gốc của câu hỏi của bạn.

Đó là một ý tưởng tốt để làm theo cách này bởi vì lệnh tạo đầu ra không được thực thi với các đặc quyền nâng cao. Điều này dường như không quan trọng ở đây echonhưng khi lệnh nguồn là một tập lệnh mà bạn không hoàn toàn tin tưởng, thì điều đó rất quan trọng.

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


Xin lỗi js3, nhưng điều này đã được đề xuất (trở lại vào năm 2008) và đang ngồi ở câu trả lời cao thứ hai: stackoverflow.com/a/82553/6910
Jonathan

2
Bạn nói đúng, Jonathan, tôi sẽ cập nhật câu trả lời của mình để mở rộng lý do tại sao đây là một lựa chọn thích hợp hơn. Cảm ơn các phản hồi hữu ích.
jg3

17

Làm sudo chạy shell, như thế này:

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

11

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

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

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

Nếu bạn cần thêm vào tập tin:

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

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

2
Nó không "khác biệt đáng kể" nhưng nó làm rõ cách sử dụng đặc biệt giữa việc thay thế và nối thêm vào tệp.
jamadagni

1
Đây là câu trả lời tôi đã sao chép vào bảng cheat của mình.
MortimerCat

5

Làm thế nào về việc 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

4

Bất cứ khi nào tôi phải làm một cái gì đó như thế này, tôi chỉ cần trở thành root:

# sudo -s
# ls -hal /root/ > /root/test.out
# exit

Nó có thể không phải là cách tốt nhất, nhưng nó hoạt động.


4

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

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

2
Điều đó thực sự có vẻ sạch hơn một chút, vì bạn không cần chỉ định rõ ràng trình bao.
Steve Bennett

1
Một nhược điểm nhỏ là nó chạy một tiến 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

3

Đừng có ý đánh bại một con ngựa chết, nhưng có quá nhiều câu trả lời ở đây sử dụng tee, điều đó có nghĩa là bạn phải chuyển hướng stdoutđến /dev/nulltrừ khi bạn muốn xem một bản sao trên màn hình.

Một giải pháp đơn giản hơn là chỉ sử dụng catnhư thế này:

sudo ls -hal /root/ | sudo bash -c "cat > /root/test.out"

Lưu ý cách chuyển hướng được đặt bên trong dấu ngoặc kép để nó được đánh giá bằng một vỏ được bắt đầu bằng sudothay vì cái chạy nó.


Điều này chỉ hoạt động tốt. Tôi không hiểu tại sao nó có một phiếu bầu tiêu cực. Nâng cao.
Teemu Leisti

4
Tôi nghĩ rằng nó không nhận được nhiều tình yêu bởi vì nó không tốt hơn nhiều sudo bash -c "ls -hal /root > /root/test.out". Sử dụng tee tránh cần vỏ, trong khi mèo thì không.
Nick Russo

2

Điều này dựa trên câu trả lời liên quan tee. Để làm cho mọi thứ dễ dàng hơn, tôi đã viết một kịch bản nhỏ (tôi gọi nó suwrite) và đưa nó vào /usr/local/bin/với sự +xcho phép:

#! /bin/sh
if [ $# = 0 ] ; then
    echo "USAGE: <command writing to stdout> | suwrite [-a] <output file 1> ..." >&2
    exit 1
fi
for arg in "$@" ; do
    if [ ${arg#/dev/} != ${arg} ] ; then
        echo "Found dangerous argument ‘$arg’. Will exit."
        exit 2
    fi
done
sudo tee "$@" > /dev/null

Như được hiển thị trong USAGE trong mã, tất cả những gì bạn phải làm là chuyển đầu ra sang tập lệnh này theo sau là tên tệp siêu người dùng có thể truy cập và nó sẽ tự động nhắc bạn nhập mật khẩu nếu cần (vì nó bao gồm sudo).

echo test | suwrite /root/test.txt

Lưu ý rằng vì đây là một trình bao bọc đơn giản cho tee, nó cũng sẽ chấp nhận -atùy chọn bổ sung của tee và cũng hỗ trợ ghi vào nhiều tệp cùng một lúc.

echo test2 | suwrite -a /root/test.txt
echo test-multi | suwrite /root/test-a.txt /root/test-b.txt

Nó cũng có một số bảo vệ đơn giản chống lại việc ghi vào /dev/các thiết bị vốn là mối quan tâm được đề cập trong một trong những bình luận trên trang này.


1

Có lẽ bạn đã được cấp quyền truy cập sudo chỉ một số chương trình / đường dẫn? Sau đó, không có cách nào để làm những gì bạn muốn. (trừ khi bạn sẽ hack nó bằng cách nào đó)

Nếu không phải như vậy thì có lẽ bạn có thể viết bash script:

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

Nhấn ctrl+ d:

chmod a+x myscript.sh
sudo myscript.sh

Hy vọng nó sẽ giúp.


1
sudo at now  
at> echo test > /tmp/test.out  
at> <EOT>  
job 1 at Thu Sep 21 10:49:00 2017  

1
Nếu bạn có sudodù sao, atkhông hữu ích hoặc cần thiết. sudo sh -c 'echo test >/tmp/test.out'thực hiện tương tự hiệu quả và thanh lịch hơn nhiều (nhưng vẫn phải chịu một lỗ hổng mà bạn có thể đang chạy mọi thứ rootmà không cần đặc quyền đó; bạn thường nên tránh các lệnh đặc quyền khi bạn có thể).
tripleee
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.