ฉันจะใช้ sudo เพื่อเปลี่ยนเส้นทางผลลัพธ์ไปยังตำแหน่งที่ฉันไม่ได้รับอนุญาตให้เขียนได้อย่างไร


881

ฉันได้รับสิทธิ์เข้าถึง sudo บนหนึ่งในกล่อง RedHat linux ที่พัฒนาของเราและดูเหมือนว่าฉันมักจะพบว่าตัวเองต้องเปลี่ยนเส้นทางไปยังตำแหน่งที่ปกติแล้วฉันไม่มีสิทธิ์เข้าถึงเพื่อเขียน

ปัญหาคือตัวอย่างที่วางแผนไว้นี้ไม่ทำงาน:

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

ฉันเพิ่งได้รับคำตอบ:

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

ฉันจะทำให้เรื่องนี้ทำงานได้อย่างไร


1
ใช้ชื่อไฟล์ chmod u + w
Szabolcs Dombi

@DombiSzabolcs คุณกำลังแนะนำให้ฉันสร้างไฟล์เป็น sudo ก่อนจากนั้นให้สิทธิ์กับตัวเองเหรอ? ความคิดที่ดี.
Jonathan

ในหลาย ๆ สถานการณ์ที่คุณมาที่นี่เพราะคุณถามว่า "ทำไมฉันถึงได้รับอนุญาตปฏิเสธ" บางครั้งคำตอบก็คือคุณจำเป็นต้องสร้างไฟล์เป็นroot(ซึ่งในกรณีนี้ให้ดำเนินการเพื่ออ่านคำตอบ) แต่บ่อยครั้งที่คุณต้องสร้างไฟล์ที่อื่นเช่นตัวคุณเอง
tripleee

1
หลังจากดิ้นรนกับคำตอบเหล่านี้ในที่สุดฉันก็เลือกที่จะเปลี่ยนเส้นทางไปยังไฟล์ชั่วคราวและ sudo ย้ายไปยังปลายทาง
TingQian LI

คำตอบ:


1233

/root/test.outคำสั่งของคุณไม่ได้เพราะการเปลี่ยนเส้นทางจะดำเนินการโดยเปลือกของคุณซึ่งไม่ได้รับอนุญาตให้เขียนไป การเปลี่ยนเส้นทางของเอาต์พุตไม่ได้ดำเนินการโดย sudo

มีหลายวิธี:

  • เรียกใช้เชลล์ด้วย sudo และให้คำสั่งโดยใช้-cตัวเลือก:

    sudo sh -c 'ls -hal /root/ > /root/test.out'
    
  • สร้างสคริปต์ด้วยคำสั่งของคุณและเรียกใช้สคริปต์นั้นด้วย sudo:

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

    sudo ls.shวิ่ง ดูคำตอบของ Steve Bennett หากคุณไม่ต้องการสร้างไฟล์ชั่วคราว

  • เรียกใช้เชลล์ด้วยsudo -sจากนั้นรันคำสั่งของคุณ:

    [nobody@so]$ sudo -s
    [root@so]# ls -hal /root/ > /root/test.out
    [root@so]# ^D
    [nobody@so]$
    
  • ใช้sudo tee(ถ้าคุณต้องหลบหนีมากเมื่อใช้-cตัวเลือก):

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

    /dev/nullจำเป็นต้องเปลี่ยนเส้นทางไปยังเพื่อหยุดทีจากการส่งออกไปยังหน้าจอ ในการผนวกแทนการเขียนทับไฟล์เอาต์พุต ( >>) ให้ใช้tee -aหรือtee --append(ไฟล์สุดท้ายเป็นไฟล์เฉพาะของGNU coreutils )

ขอบคุณไปที่Jd , Adam J. ForsterและJohnathanสำหรับแนวทางที่สองสามและสี่


1
มีคำตอบที่ดีที่จะบอกคุณถึงวิธีการเปลี่ยนเส้นทาง STDERR และ STDOUT แยกกันที่นี่: stackoverflow.com/questions/692000/… ... โดยทั่วไปperl -e 'print "STDIN\n"; print STDERR "STDERR\n"; ' > >( tee stdout.log ) 2> >( tee stderr.log >&2 )
errant.info

2
คุณจะต้องทำ 'sudo -E ... ' เพื่อใช้ตัวแปรในคำสั่ง shelled out (เช่นเมื่อใช้สคริปต์นี้ในสคริปต์)
Urhixidur

3
การเปลี่ยนทิศทางทีออฟเอาต์พุตไปยัง / dev / null อาจไม่จำเป็นในหลาย ๆ กรณีที่การสะท้อนเอาต์พุตไปที่หน้าจอไม่เป็นอันตราย ตัวอย่างเช่นเมื่อจัดการกับเอาต์พุตของคำสั่งปกติหรือเนื้อหาของไฟล์ข้อความขนาดเล็ก
thomasrutter

105

ใครบางคนที่นี่เพิ่งแนะนำ sudoing ที:

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

นอกจากนี้ยังสามารถใช้เพื่อเปลี่ยนเส้นทางคำสั่งใด ๆ ไปยังไดเรกทอรีที่คุณไม่สามารถเข้าถึงได้ ใช้งานได้เพราะโปรแกรม tee เป็นโปรแกรม "echo to a file" อย่างมีประสิทธิภาพและการเปลี่ยนเส้นทางไปยัง / dev / null ก็คือการหยุดมันด้วยการส่งออกไปยังหน้าจอเพื่อให้มันเหมือนกับตัวอย่างต้นฉบับที่ประดิษฐ์ไว้ด้านบน


5
ในหลายกรณีกล่าวคือหากผู้ใช้ปกติมี prmissions เพื่อดำเนินการคำสั่งและ "เท่านั้น" ไม่สามารถเขียนไปยังไฟล์เอาต์พุตที่ต้องการsudoได้อาจจะตัดการใช้งานแรก(เช่นสำหรับคำสั่งด้วยตัวเอง)
Hagen von Eitzen

81

เคล็ดลับที่ฉันคิดออกเองก็คือ

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

16
sudo ddดีกว่าsudo tee /root/file > /dev/nullตัวอย่างด้านบน!
kristianlm

14
dd ไม่ใช่คำสั่งปิดบังแปลก ๆ มันถูกใช้เมื่อใดก็ตามที่คุณต้องการคัดลอกข้อมูลจำนวนมากพร้อมบัฟเฟอร์ระหว่างอุปกรณ์บล็อกสองเครื่อง ไวยากรณ์นั้นค่อนข้างเรียบง่ายจริงๆddคือชื่อคำสั่งof=/root/test.outเป็นอาร์กิวเมนต์ที่บอกddว่าไฟล์เอาต์พุตคืออะไร
rhlee

14
@ สตีฟทุกอย่าง 'คลุมเครือ' จนกว่าคุณจะเรียนรู้ว่ามันคืออะไร ofหมายถึงไฟล์เอาต์พุตและddเป็นเครื่องมือยอดนิยมที่ใช้ทั้ง Linux และ OSX (ส่วนใหญ่ใช้สำหรับการเขียนภาพไปยังดิสก์) นี่เป็นเคล็ดลับที่เรียบร้อยแน่นอน
blockloop

12
ddอาจมีประโยชน์เท่ากันteeที่นี่ ในทั้งสองกรณีคุณกำลังใช้คำสั่งทั่วไปที่รู้จักกันดีสำหรับจุดประสงค์ที่ในขณะที่แตกต่างจากจุดประสงค์ดั้งเดิมดั้งเดิมเล็กน้อย แต่ก็ยังเป็นที่รู้จักและมีเอกสารดี ในขณะddที่การคัดลอกข้อมูลจำนวนมากทำได้ดี แต่ก็ไม่ได้ดูดข้อมูลจำนวนน้อย มันมีประโยชน์ที่นี่ไม่ได้สะท้อนการส่งออกไปยังออกมาตรฐานเช่นกัน
thomasrutter

26
เมื่อใดก็ตามที่คุณพิมพ์คำsudo ddต่อไปกับอีกคนหนึ่งที่คุณต้องการให้มากมากแน่ใจว่าข้อโต้แย้งที่เป็นไปตามถูกต้อง (โดยเฉพาะการพิจารณาไวยากรณ์ที่ไม่ได้มาตรฐานของมัน) พวกเขาไม่เรียกมันว่า "disk destroyer" โดยไม่ทำอะไรเลย ...
ali_m

45

ปัญหาคือว่าคำสั่งทำงานภายใต้sudoแต่การเปลี่ยนเส้นทางจะทำงานภายใต้ผู้ใช้ของคุณ สิ่งนี้ทำโดยเชลล์และมีน้อยมากที่คุณสามารถทำได้

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

วิธีปกติของการเลี่ยงผ่านสิ่งนี้คือ:

  • ตัดคำสั่งในสคริปต์ที่คุณเรียกใช้ภายใต้ sudo

    หากคำสั่งและ / หรือล็อกไฟล์เปลี่ยนแปลงคุณสามารถทำให้สคริปต์ใช้สิ่งเหล่านี้เป็นอาร์กิวเมนต์ ตัวอย่างเช่น:

    sudo log_script command /log/file.txt
    
  • เรียกเชลล์และส่งบรรทัดคำสั่งเป็นพารามิเตอร์ด้วย -c

    สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับคำสั่งปิดหนึ่งคำสั่ง ตัวอย่างเช่น:

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

23

อีกความแตกต่างในชุดรูปแบบ:

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

หรือแน่นอน:

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

พวกเขามี (เล็ก ๆ ) ประโยชน์ที่คุณไม่จำเป็นต้องจำข้อโต้แย้งใด ๆ กับsudoหรือsh/bash


18

ชี้แจงเล็กน้อยว่าทำไมตัวเลือกทีออฟจึงดีกว่า

สมมติว่าคุณมีสิทธิ์ที่เหมาะสมในการเรียกใช้งานคำสั่งที่สร้างเอาต์พุตหากคุณไพพ์เอาต์พุตของคำสั่งของคุณเป็น tee คุณจะต้องยกระดับสิทธิพิเศษของ tee ด้วย sudo และ tee โดยตรงเพื่อเขียน (หรือผนวก) ไปยังไฟล์ที่เป็นปัญหา

ในตัวอย่างที่ให้ไว้ในคำถามที่จะหมายถึง:

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

สำหรับตัวอย่างที่ใช้งานได้จริงมากขึ้น:

# 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

ในแต่ละตัวอย่างเหล่านี้คุณกำลังใช้เอาต์พุตของคำสั่งที่ไม่มีสิทธิพิเศษและเขียนลงในไฟล์ที่โดยปกติจะเขียนได้โดย root ซึ่งเป็นจุดเริ่มต้นของคำถามของคุณ

มันเป็นความคิดที่ดีที่จะทำเช่นนี้เพราะคำสั่งที่สร้างเอาท์พุทไม่ได้ถูกดำเนินการด้วยสิทธิ์ยกระดับ ดูเหมือนจะไม่สำคัญที่นี่ด้วยechoแต่เมื่อคำสั่ง source เป็นสคริปต์ที่คุณไม่ไว้วางใจอย่างสมบูรณ์มันเป็นสิ่งสำคัญ

หมายเหตุคุณสามารถใช้ตัวเลือก -a เพื่อทีจะต่อท้าย (เช่น>>) ต่อท้ายไฟล์เป้าหมายแทนที่จะเขียนทับ (เช่น>)


ขออภัย js3 แต่สิ่งนี้ได้รับการแนะนำแล้ว (ย้อนกลับไปในปี 2008) และอยู่ที่คำตอบที่สูงที่สุดอันดับสอง: stackoverflow.com/a/82553/6910
Jonathan

2
คุณพูดถูกโจนาธานฉันจะอัปเดตคำตอบของฉันเพื่อขยายเหตุผลว่าทำไมตัวเลือกนี้จึงเป็นตัวเลือกที่ดีกว่า ขอบคุณสำหรับคำติชมที่เป็นประโยชน์
jg3


11

วิธีที่ฉันจะไปเกี่ยวกับปัญหานี้คือ:

หากคุณต้องการเขียน / แทนที่ไฟล์:

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

หากคุณต้องการต่อท้ายไฟล์:

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

1
สิ่งนี้แตกต่างอย่างมากกับคำตอบข้างต้นอย่างไร
Jonathan

2
ไม่ใช่ "แตกต่างอย่างมีนัยสำคัญ" แต่จะอธิบายการใช้งานที่โดดเด่นระหว่างการแทนที่และการต่อท้ายไฟล์
jamadagni

1
นี่คือคำตอบที่ฉันคัดลอกไปยังแผ่นงานโกงของฉัน
MortimerCat

5

วิธีการเกี่ยวกับการเขียนสคริปต์?

ชื่อไฟล์: myscript

#!/bin/sh

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

# end script

จากนั้นใช้ sudo เพื่อเรียกใช้สคริปต์:

sudo ./myscript

4

เมื่อใดก็ตามที่ฉันต้องทำอะไรเช่นนี้ฉันก็จะกลายเป็นราก:

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

อาจไม่ใช่วิธีที่ดีที่สุด แต่ใช้ได้


4

ฉันจะทำแบบนี้:

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

2
ที่จริงแล้วค่อนข้างสะอาดกว่าเนื่องจากคุณไม่จำเป็นต้องระบุเชลล์อย่างชัดเจน
Steve Bennett

1
หนึ่งข้อเสียเปรียบเล็กน้อยคือมันทำงานหนึ่งกระบวนการเพิ่มเติม ( 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

ไม่ได้หมายถึงการเอาชนะม้าที่ตายแล้ว แต่มีคำตอบให้ใช้มากเกินไปteeซึ่งหมายความว่าคุณต้องเปลี่ยนเส้นทางstdoutไป/dev/nullเว้นแต่คุณต้องการเห็นสำเนาบนหน้าจอ

วิธีที่ง่ายกว่าคือการใช้catสิ่งนี้:

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

สังเกตว่าการเปลี่ยนเส้นทางถูกใส่ไว้ในเครื่องหมายคำพูดอย่างไรเพื่อให้เชลล์ถูกประเมินโดยเชลล์ที่สตาร์ทโดยsudoแทนที่จะเป็นเชลล์ที่รันอยู่


มันใช้งานได้ดี ฉันไม่เข้าใจว่าทำไมจึงมีการลงคะแนนเชิงลบหนึ่ง upvoted
Teemu Leisti

4
ฉันคิดว่ามันไม่ได้รับความรักมากนักเพราะมันไม่ได้ดีไปกว่าsudo bash -c "ls -hal /root > /root/test.out"นี้อีกแล้ว การใช้ทีหลีกเลี่ยงการต้องการเชลล์ในขณะที่แมวไม่ได้ทำ
Nick Russo

2

teeนี้จะขึ้นอยู่กับคำตอบที่เกี่ยวข้องกับ ที่จะทำให้สิ่งที่ง่ายขึ้นผมเขียนสคริปต์ขนาดเล็ก (ผมเรียกมันว่าsuwrite) และวางไว้ใน/usr/local/bin/ที่มี+xได้รับอนุญาต:

#! /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

ตามที่ปรากฏในการใช้งานในรหัสทั้งหมดที่คุณต้องทำคือการท่อส่งออกไปยังสคริปต์นี้ตามด้วยชื่อไฟล์ที่สามารถเข้าถึง superuser ต้องการและมันก็จะแจ้งให้คุณโดยอัตโนมัติสำหรับรหัสผ่านของคุณหากจำเป็น (เพราะมันรวมถึงsudo)

echo test | suwrite /root/test.txt

โปรดทราบว่าเนื่องจากนี่เป็นเสื้อคลุมเรียบง่ายสำหรับteeมันจะยอมรับ-aตัวเลือกของ tee เพื่อผนวกและยังรองรับการเขียนไปยังหลายไฟล์ในเวลาเดียวกัน

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

นอกจากนี้ยังมีการป้องกันแบบง่าย ๆ ในการเขียนไปยัง/dev/อุปกรณ์ซึ่งเป็นข้อกังวลที่กล่าวถึงในความคิดเห็นในหน้านี้


1

บางทีคุณอาจได้รับสิทธิ์เข้าถึง sudo เฉพาะบางโปรแกรม / เส้นทาง จากนั้นไม่มีทางที่จะทำสิ่งที่คุณต้องการ (เว้นแต่คุณจะแฮ็คมันอย่างใด)

หากไม่ใช่กรณีนั้นคุณสามารถเขียนสคริปต์ทุบตีได้:

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

กดctrl+ d:

chmod a+x myscript.sh
sudo myscript.sh

หวังว่ามันจะช่วย


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

1
หากคุณมีsudoอยู่แล้วatไม่มีประโยชน์หรือจำเป็น sudo sh -c 'echo test >/tmp/test.out'ทำสิ่งเดียวกันได้อย่างมีประสิทธิภาพและสวยงามยิ่งขึ้น (แต่ยังคงมีปัญหาจากข้อบกพร่องที่คุณอาจเรียกใช้ในสิ่งrootที่ไม่ต้องการสิทธิ์นั้นโดยทั่วไปคุณควรหลีกเลี่ยงคำสั่งพิเศษเมื่อคุณทำได้)
tripleee
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.