การเปลี่ยนเส้นทาง stdout ไปยังไฟล์ที่คุณไม่ได้รับอนุญาตให้เขียน


113

เมื่อคุณพยายามแก้ไขไฟล์โดยไม่ได้รับอนุญาตให้เขียนคุณจะได้รับข้อผิดพลาด:

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

Sudoing ไม่ได้ช่วยเพราะมันรันคำสั่งในฐานะ root แต่เชลล์จัดการการเปลี่ยนเส้นทาง stdout และเปิดไฟล์เหมือนคุณ

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

มีวิธีง่าย ๆ ในการเปลี่ยนเส้นทาง stdout ไปยังไฟล์ที่คุณไม่ได้รับอนุญาตให้เขียนนอกจากเปิดเชลล์เป็นรูทและจัดการไฟล์ด้วยวิธีนี้หรือไม่?

> sudo su
# echo test > /tmp/foo

2
คำตอบสำหรับคำถามที่คล้ายกันจาก StackOverflow stackoverflow.com/questions/82256/…
Cristian Ciupitu

คุณจะไม่มีสิทธิ์ในไฟล์ที่คุณสร้างด้วยตัวเองใน tmp ได้อย่างไร? มันเป็นเพราะ umask หรือไม่?
k961

@ k961 ฉันเคยchownเปลี่ยนเจ้าของ มันเป็นเพียงตัวอย่าง
Michael Mrozek

คำตอบ:


116

teeใช่ใช้ ดังนั้นecho test > /tmp/fooกลายเป็น

echo test | sudo tee /tmp/foo

คุณสามารถต่อท้าย ( >>)

echo test | sudo tee -a /tmp/foo

27
Tee จะส่งออกไปยัง stdout; บางครั้งคุณไม่ต้องการให้เนื้อหาเต็มหน้าจอ ในการแก้ไขปัญหานี้ให้ทำecho test | sudo tee /tmp/foo > /dev/null
Shawn J. Goff

คุณจะทำอย่างไรกับ heredoc
JohnDoea

26

เพื่อแทนที่เนื้อหาของไฟล์ด้วยผลลัพธ์ของecho(เช่นตัว>ดำเนินการเปลี่ยนเส้นทางเชลล์)

echo test | sudo dd of=/tmp/foo

หากต้องการเขียนลงในไฟล์ (ที่จุดเริ่มต้นถึงแม้ว่าคุณสามารถใช้seekเพื่อเอาท์พุทที่แตกต่างกัน offsets) โดยไม่ต้องตัดทอน (เช่น1<>ผู้ประกอบการเชลล์บอร์น):

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

หากต้องการต่อท้ายไฟล์ (เช่น>>) ด้วย GNU dd:

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

ดูเพิ่มเติม GNU dd's conv=exclเพื่อหลีกเลี่ยงการ clobbering ไฟล์ที่มีอยู่ (เช่นเดียวกับset -o noclobberในเปลือกหอย POSIX) และconv=nocreatสำหรับตรงข้าม (เฉพาะอัพเดตไฟล์ที่มีอยู่)


ฉลาด! สิ่งนี้จะช่วยลดความจำเป็นที่ต้องทำecho test | sudo tee /tmp/foo >/dev/nullเพื่อทิ้งเอาต์พุต
Adam Katz

2
ฉันอาจจะต้องเอามันกลับมา; ddไม่น่าเชื่อถือสำหรับสิ่งนั้นเว้นแต่ว่าคุณใช้ตัวเลือกที่ไม่ชัดเจนของ GNU เท่านั้นiflag=fullblock oflag=fullblockซึ่งเป็นการลบความงดงามของคำตอบนี้ teeฉันจะติดกับ
Adam Katz

5
ววเชื่อถือได้กับ non-obscure bs = 1
umeboshi

2
@umeboshi แต่เชื่อถือได้ก็ต่อเมื่อคุณมีประสบการณ์มากพอที่จะรู้ว่าคุณกำลังทำอะไรอยู่ เพราะddอาจเป็นอันตรายพอสมควร (ถ้าไม่พูด: ทำลายล้าง) หากทำผิดพลาดเพียงเล็กน้อย ดังนั้นสำหรับผู้ใช้ใหม่ฉันอยากจะแนะนำteeวิธีการที่จะอยู่บนฝั่งที่ปลอดภัย
ไวยากรณ์

1
@ AdamKatz ในกรณีของdd of=fileคนเดียว (โดยไม่ต้องcount/ skip... ) มีความน่าเชื่อถือ iflag=fullblockไม่จำเป็นเนื่องจากที่นี่ddเขียนบนเอาต์พุตสิ่งที่อ่านบนอินพุต มันไม่สำคัญว่ามันจะไม่ใช่บล็อกเต็มหรือไม่
Stéphane Chazelas

12

tee อาจเป็นตัวเลือกที่ดีที่สุด แต่ขึ้นอยู่กับสถานการณ์ของคุณสิ่งนี้อาจเพียงพอ:

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

1
3 ปัญหา: evalแทนง่ายsh -c; - ฉันซึ่งจะเปลี่ยน dir ทำงานของคุณ; ใช้คำสั่งทั้งหมดเป็นรูทซึ่งอาจเปลี่ยนพฤติกรรมหรืออาจมีความเสี่ยงที่ไม่จำเป็น ทำไมสิ่งนี้ถึงได้รับ upvote

4
คุณไม่ได้ แต่มันทำให้เข้าใจผิดโดยทั่วไปไม่ดีและอาจเป็นอันตรายได้

5

ขณะที่ฉันเห็นว่า| sudo teeเป็นวิธีที่ยอมรับบางครั้งsed (ที่นี่สมมติ GNU sed) อาจทำงาน:

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

-iแก้ไขไฟล์ให้เข้าที่ 1iหมายถึงการแทรกก่อนบรรทัด 1 $aหมายถึงการผนวกหลังจากบรรทัดสุดท้าย

หรือคัดลอกไปยัง xclipboard:

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

1
นี่เป็นคำพูดที่เป็นปริศนาจีนโบราณ ไม่เห็นที่จะเข้าใจว่าสิ่งนี้มี upvotes มากมาย ( hrmph )
syntaxerror

1
@syntaxerror: ครับผมขอโทษผมไม่ใช่คนพูดภาษาอังกฤษ หากคุณระบุสิ่งที่ไม่ชัดเจนสำหรับคุณฉันสามารถลองปรับปรุงคำตอบของฉันได้ เมื่อเทียบกับ 65 upvotes สำหรับ Gert ดูเหมือนว่า 4 จะไม่ใช่ upvotes มากมายเช่นกันคุณไม่คิดเหรอ?
ผู้ใช้ไม่ทราบเมื่อ

ฉันจะพอใจกับ 4 :-D ภาษาอังกฤษของคุณไม่เลวเลย มันเป็นเพียงคำศัพท์ในรูปแบบของ terse techie nerdspeak ฉันต้องเดาว่าคุณเป็น coder ผู้เขียนโค้ดระหว่างกันจะเข้าใจตัวเองอย่างสมบูรณ์แบบเช่นนั้น แต่ผู้ที่ไม่ได้เข้ารหัสต้องคิดว่ามันเป็นคำพูดเหมือน ... ดังที่กล่าวไว้
ไวยากรณ์

โปรดทราบsed -iว่าไม่ได้แก้ไขไฟล์ในสถานที่จริง - มันจะสร้างไฟล์ชั่วคราวและเปลี่ยนชื่อเมื่อออกจาก ดังนั้นคุณจะไม่สามารถทำบางสิ่งเช่นtail -f ...ไฟล์ต้นฉบับและดูผลลัพธ์โดยใช้sed -i ...ขณะที่
ไพพ์

@AndrewHenle: ใช่เนื่องจากขนาดอาจเพิ่มขึ้นหรือลดขนาดลงและอาจเป็นกรณีของการเรียกร้องที่น่ารำคาญที่สุดและคุณไม่สามารถแม้แต่จะ afaik - เขียนไปยังตำแหน่งเดียวกันบน SSD มันเป็นเพียงการดำเนินการหลอก 'แทน' . ในฐานะที่เป็นผู้พูดภาษาอังกฤษที่ไม่ใช่เจ้าของภาษาฉันขอการแสดงออกโดยย่อซึ่งไม่น่าจะตีความผิดได้ เพียงแค่-i creates a new file of same nameมีบางสิ่งที่กะทัดรัดกว่านี้หรือไม่? ผมคิดว่าผมชอบเพราะมันอธิบายin place imanpage GNU-sed เรียกมันว่าในสถานที่--in-placeเกินไปและธงยาว
ผู้ใช้ที่ไม่รู้จัก

2

ฉันได้รับการเตะไปรอบ ๆ ในด้านหลังของความคิดความคิดของฉันสำหรับปัญหาที่คล้ายกันและมากับวิธีการแก้ปัญหาต่อไปนี้:

  • sudo uncatซึ่งuncatเป็นโปรแกรมที่อ่านเข้ามาตรฐานและเขียนไปยังแฟ้มที่มีชื่อในบรรทัดคำสั่ง แต่ฉันยังไม่ได้เขียนuncatเลย

  • sudocatแตกต่างจากsudoeditที่ผมยังไม่ได้เขียนเลยที่ไม่สะอาดหรือsudo catsudo uncat

  • หรือเคล็ดลับเล็กน้อยในการใช้sudoeditกับ EDITOR ที่เป็นเชลล์สคริปต์

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

    ซึ่งสามารถเรียกใช้เป็นอย่างใดอย่างหนึ่ง|sudo ./uncat fileหรือ| EDITOR=./uncat sudoeditแต่ที่มีผลข้างเคียงที่น่าสนใจ


catใช้รายการของไฟล์เพื่อ con cat inate ดังนั้น uncat ควรใช้รายการของไฟล์ที่จะไม่ con cat inate มันจะต้องใช้เวทย์มนตร์ในการตัดสินใจว่าจะใส่ในแต่ละไฟล์มากแค่ไหน ชื่อทางเลือกรวมถึงdog, ,to-file redirect
ctrl-alt-delor

ฉันไม่สามารถคิดเหตุผลใดทำไมฉันต้องการเมื่อฉันมีuncat tee
Wildcard

1
ดีteeมีอุปสรรคเล็ก ๆ น้อย ๆ ว่ามันเขียน stdin เพื่อ stdout ของ - ซึ่งจะลดลงนิด ๆ /dev/nullโดยเปลี่ยนทิศไป ทางเลือกอื่น ๆ ได้แก่dd of=/tmp/foo(กล่าวถึงในคำตอบอื่น) ซึ่งเขียนข้อมูลสถานะการ stderr cp /dev/stdin /tmp/fooและ
สกอตต์

1

ใช้ฟองน้ำจากแพ็คเกจ moreutils มันมีข้อได้เปรียบที่ไม่ได้เขียนถึง stdout

echo test | sudo sponge /tmp/foo

ใช้ตัวเลือก -a เพื่อต่อท้ายไฟล์แทนการเขียนทับมัน


1
ฉันไม่แน่ใจว่าข้อได้เปรียบอะไรที่ไม่ได้เขียนถึง stdout แต่คุณสามารถเปลี่ยนเส้นทางผลลัพธ์ไป/dev/nullที่ปัญหาได้
Michael Mrozek

1
แน่นอนฉันสามารถเปลี่ยนเส้นทางไปยัง / dev / null แต่คำสั่งนั้นง่ายต่อการอ่านและพิมพ์โดยไม่มีการเปลี่ยนเส้นทาง ข้อดีของการไม่เขียนถึง stdout ก็คือเทอร์มินัลของฉันไม่เต็มไปด้วยขยะ
Hontvári Levente

1
ฉันจะไม่ติดตั้งแพ็คเกจเพื่อเปลี่ยนเส้นทาง แต่ฉันใช้ฟองน้ำเป็นประจำดังนั้นจึงมีอยู่แล้ว
Hontvári Levente

0

ข้อผิดพลาดมาจากลำดับที่เชลล์ทำสิ่งต่าง ๆ

การเปลี่ยนเส้นทางได้รับการจัดการก่อนที่เชลล์จะเรียกใช้งานsudoดังนั้นจึงทำโดยได้รับอนุญาตจากผู้ใช้ที่คุณใช้งานอยู่ เนื่องจากคุณไม่มีสิทธิ์ในการเขียนเพื่อสร้าง / ตัดปลายเป้าหมายของการเปลี่ยนเส้นทางคุณจะได้รับpermission deniedข้อผิดพลาดจากเชลล์

ทางออกคือรับประกันว่าไฟล์เอาต์พุตจะถูกสร้างขึ้นภายใต้ข้อมูลประจำตัวที่คุณได้รับsudoเช่นtee:

$ generate_output | sudo tee target_file
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.