ตามที่ @geekosaur อธิบายเชลล์จะทำการเปลี่ยนเส้นทางก่อนที่จะรันคำสั่ง เมื่อคุณพิมพ์สิ่งนี้:
sudo foo >/some/file
กระบวนการเชลล์ปัจจุบันของคุณสร้างสำเนาของตัวเองที่พยายามเปิดขึ้น/some/fileเพื่อเขียนเป็นครั้งแรกจากนั้นหากประสบความสำเร็จจะทำให้ไฟล์นั้นเป็นตัวอธิบายเอาต์พุตมาตรฐานและเฉพาะในกรณีที่ประสบความสำเร็จเท่านั้นจึงจะดำเนินการsudoได้ นี่คือความล้มเหลวในขั้นตอนแรก
หากคุณได้รับอนุญาต (การกำหนดค่า sudoer มักจะไม่รวมเชลล์ที่กำลังรันอยู่) คุณสามารถทำสิ่งนี้ได้:
sudo bash -c 'foo >/some/file'
แต่ฉันคิดว่าเป็นทางออกที่ดีโดยทั่วไปคือการใช้| sudo teeแทน>และแทน| sudo tee -a >>นี่เป็นประโยชน์อย่างยิ่งหากการเปลี่ยนเส้นทางเป็นเหตุผลเดียวที่ฉันต้องการsudoตั้งแต่แรก ท้ายที่สุดกระบวนการทำงานโดยไม่จำเป็นเนื่องจากรูทเป็นสิ่งที่sudoสร้างขึ้นเพื่อหลีกเลี่ยง และการทำงานechoในฐานะรูทนั้นโง่มาก
echo '[archlinuxfr]' | sudo tee -a /etc/pacman.conf >/dev/null
echo 'Server = http://repo.archlinux.fr/$arch' | sudo tee -a /etc/pacman.conf >/dev/null
echo ' ' | sudo tee -a /etc/pacman.conf >/dev/null
ฉันเพิ่ม> /dev/nullที่สิ้นสุดเพราะteeส่งออกของไปทั้งไฟล์ชื่อและออกมาตรฐานของตัวเองและฉันไม่ต้องการที่จะเห็นมันใน terminal ของฉัน ( teeคำสั่งทำหน้าที่เหมือนตัวเชื่อมต่อ "T" ในไปป์ไลน์ทางกายภาพซึ่งเป็นที่มาของชื่อ) และฉันเปลี่ยนไปใช้เครื่องหมายคำพูดเดี่ยว ( '... ') แทนที่จะเป็นคู่ ( "... ") เพื่อให้ทุกอย่างเป็นตัวอักษรและฉัน ไม่ต้องใส่เครื่องหมายในด้านหน้าของใน$ $arch(หากไม่มีเครื่องหมายคำพูดหรือแบ็กสแลช$archจะถูกแทนที่ด้วยค่าของพารามิเตอร์เชลล์archซึ่งอาจไม่มีอยู่จริงซึ่งในกรณีนี้$archจะถูกแทนที่ด้วยอะไรและหายไป)
ดังนั้นจะดูแลการเขียนไปยังไฟล์เป็นรูทโดยใช้sudo. ตอนนี้สำหรับการพูดนอกเรื่องที่มีความยาวเกี่ยวกับวิธีการส่งออกข้อความที่มีขึ้นบรรทัดใหม่ในเชลล์สคริปต์ :)
หากต้องการ BLUF อย่างที่พวกเขากล่าวทางออกที่ฉันต้องการคือเพียงแค่ป้อนเอกสารที่นี่ลงในsudo teeคำสั่งด้านบน จากนั้นไม่จำเป็นต้องมีcatหรือechoหรือprintfหรือคำสั่งอื่นใดเลย เครื่องหมายคำพูดเดี่ยวได้ย้ายไปที่คำนำของ Sentinel <<'EOF'แต่มีผลเหมือนกันที่นั่น: เนื้อหาจะถือว่าเป็นข้อความตามตัวอักษรดังนั้นจึง$archถูกทิ้งไว้ตามลำพัง:
sudo tee -a /etc/pacman.conf >/dev/null <<'EOF'
[archlinuxfr]
Server = http://repo.archlinux.fr/$arch
EOF
แต่ในขณะที่ฉันทำมันก็มีทางเลือกอื่น นี่คือบางส่วน:
คุณสามารถใช้หนึ่งรายการechoต่อบรรทัด แต่จัดกลุ่มทั้งหมดเข้าด้วยกันใน subshell ดังนั้นคุณจะต้องต่อท้ายไฟล์เพียงครั้งเดียว:
(echo '[archlinuxfr]'
 echo 'Server = http://repo.archlinux.fr/$arch'
 echo ' ') | sudo tee -a /etc/pacman.conf >/dev/null
หากคุณเพิ่มลง-eในecho(และคุณกำลังใช้เชลล์ที่รองรับส่วนขยายที่ไม่ใช่ POSIX นั้น) คุณสามารถฝังบรรทัดใหม่ลงในสตริงได้โดยตรงโดยใช้\n:
echo -e '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | 
  sudo tee -a /etc/pacman.conf >/dev/null
แต่ตามที่กล่าวไว้ข้างต้นนั่นไม่ใช่พฤติกรรมที่ระบุโดย POSIX เชลล์ของคุณอาจแค่สะท้อนลิเทอรัล-eตามด้วยสตริงที่มีตัวอักษรจำนวน\nมากแทน วิธี POSIX คือการใช้printfแทนecho; มันจะถือว่าอาร์กิวเมนต์ของมันโดยอัตโนมัติเช่นเดียวกับecho -eแต่จะไม่ต่อท้ายบรรทัดใหม่โดยอัตโนมัติดังนั้นคุณต้องติดเพิ่มที่\nนั่นด้วย:
printf '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n \n' | 
  sudo tee -a /etc/pacman.conf >/dev/null
ด้วยวิธีแก้ปัญหาเหล่านี้สิ่งที่คำสั่งได้รับเป็นสตริงอาร์กิวเมนต์ประกอบด้วยลำดับสองอักขระ\nและขึ้นอยู่กับโปรแกรมคำสั่งเอง (โค้ดภายในprintfหรือecho) เพื่อแปลสิ่งนั้นเป็นบรรทัดใหม่ ในเชลล์สมัยใหม่จำนวนมากคุณมีตัวเลือกในการใช้เครื่องหมายคำพูด ANSI $'... 'ซึ่งจะแปลลำดับเช่น\nเป็นบรรทัดใหม่ตามตัวอักษรก่อนที่โปรแกรมคำสั่งจะเห็นสตริง นั่นหมายความว่าสตริงดังกล่าวทำงานร่วมกับคำสั่งใดก็ได้รวมถึง old -e-less ธรรมดาecho:
echo $'[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | 
  sudo tee -a /etc/pacman.conf >/dev/null
แต่ในขณะที่พกพาได้ง่ายกว่าecho -eราคา ANSI ก็ยังคงเป็นส่วนขยายที่ไม่ใช่ POSIX
และอีกครั้งในขณะที่สิ่งเหล่านี้เป็นตัวเลือกทั้งหมดฉันชอบtee <<EOFวิธีแก้ปัญหาที่ตรงด้านบน