Sudo cat neden izin verilmediğini verirken sudo vim neden iyi çalışıyor?


87

Arch'ımın pacman.conf dosyasına bir depo kaynağının eklenmesini otomatikleştirmeye çalışıyorum, ancak echokabuk komut dosyamdaki komutu kullanıyorum . Ancak şu şekilde başarısız olur: -

sudo echo "[archlinuxfr]" >> /etc/pacman.conf
sudo echo "Server = http://repo.archlinux.fr/\$arch" >> /etc/pacman.conf
sudo echo " " >> /etc/pacman.conf

-bash: /etc/pacman.conf: Permission denied

/Etc/pacman.conf dosyasında vim kullanarak manuel olarak değişiklik yaparsam,

sudo vim /etc/pacman.conf

ve :wqvim'den çıkıldığında her şey yolunda gidiyor ve pacman.conf'um "İzin reddedildi" şikayetleri olmadan manuel olarak güncellendi.

Bu neden böyle? Ve sudo echoişe nasıl başlarım ? (btw, ben sudo catde kullanmayı denedim ama bu da İzin reddedildiği için başarısız oldu)


Yanıtlar:


52

Sorun, yeniden yönlendirmenin, tarafından değil, orijinal kabuğunuz tarafından işleniyor olmasıdır sudo. Kabuklar zihinleri okuyamazlar ve bu özelliğin >>onun için sudodeğil, için olduğunu bilmezler .

Gerek:

  1. yönlendirmeyi alıntılayın (böylece yönlendirilir sudo)
  2. ve kullanın sudo -s(böylece sudo, alıntılanan yönlendirmeyi işlemek için bir kabuk kullanır.)

1
Yani bunu iki adımda yapmak (1) sudo -s(2) echo "# test" >> /etc/pacman.conf çalışır. Ama bunu tek bir satırda yürütmek mümkün mü?
Calvin Cheng

15
sudo -s 'echo "# test" >>/etc/pacman.conf'sana iletmeye çalıştığım şeydi.
geekosaur

2
Aslında, yukarıdaki cevabınızı okuduktan sonra bunu denedim ama şöyle garip bir hata aldım: - sudo -s 'echo "# test" >> /etc/pacman.conf' /bin/bash: echo "# test" >> /etc/pacman.conf: No such file or directorybu yüzden daha sonra 2 adımlı manuel işlemi denedim.
Calvin Cheng

16
Ah ..... bu şekilde son bir deneme işe yaradı -echo 'echo "# test" >> /etc/pacman.conf' | sudo -s
Calvin Cheng

1
sudoYapılandırmanın devre dışı bırakılması hakkında nasıl / nereden bilgi edinebilirim -s? visudo?
Calvin Cheng

129

@Geekosaur'un açıkladığı gibi, kabuk komutu çalıştırmadan önce yönlendirmeyi yapar. Bunu yazdığınızda:

sudo foo >/some/file

Mevcut kabuk işleminiz, önce /some/fileyazmak için açmaya çalışan kendisinin bir kopyasını oluşturur , daha sonra başarılı olursa, o dosya tanımlayıcısını standart çıktısı yapar ve yalnızca başarılı olursa çalıştırılır sudo. Bu ilk adımda başarısız oluyor.

İzin veriliyorsa (sudoer yapılandırmaları genellikle kabukların çalıştırılmasını engeller), şöyle bir şey yapabilirsiniz:

sudo bash -c 'foo >/some/file'

Ama genel olarak | sudo teeyerine >ve | sudo tee -ayerine kullanmak iyi bir çözüm buluyorum >>. Bu, özellikle yeniden yönlendirme ihtiyacım olan tek nedeyse yararlıdır sudo; Sonuçta, gereksiz yere kök olarak çalışan süreçler, tam sudoolarak kaçınmak için yaratılan şeydir . Ve echokök olarak çalıştırmak çok aptalca.

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/nullSonunda ekledim çünkü teeçıktısını hem adlandırılmış dosyaya hem de kendi standart çıktısına gönderiyor ve onu terminalimde görmeme gerek yok. ( teeKomut. Bu adı aldığı nerede fiziksel testlere boru hattında "T" konnektör gibi davranır) Ve (tek tırnak geçti '... '(çiftler yerine) "... "her şeyin değişmez ve ben bu yüzden) önüne ters eğik çizgi yoktu $in $arch. (Tırnak işaretleri veya ters eğik çizgi olmadan, muhtemelen mevcut olmayan $archkabuk parametresinin değeri ile değiştirilirdi arch, bu durumda $archhiçbir şeyle değiştirilir ve ortadan kaybolur.)

Böylece dosyalara root kullanarak yazmayı halleder sudo. Şimdi, bir kabuk betiğinde satırsonu içeren metinlerin çıktısını almanın yolları hakkında uzun bir araştırma. :)

BLUF için, dedikleri gibi, tercih ettiğim çözüm, yukarıdaki sudo teekomuta sadece bir buradaki belgeyi beslemek olurdu ; o zaman catya echoya printfda ya da başka herhangi bir komuta gerek yoktur . Tek tırnak işaretleri, sentinel giriş kısmına taşındı <<'EOF', ancak burada aynı etkiye sahipler: beden, gerçek metin olarak değerlendirildi, bu yüzden $archyalnız bırakıldı:

sudo tee -a /etc/pacman.conf >/dev/null <<'EOF'
[archlinuxfr]
Server = http://repo.archlinux.fr/$arch

EOF

Ama ben böyle yapsam da alternatifler var. Burda biraz var:

echoHer satıra bir tane yapıştırabilirsiniz , ancak hepsini bir alt kabukta gruplayabilirsiniz, böylece dosyaya yalnızca bir kez eklemeniz gerekir:

(echo '[archlinuxfr]'
 echo 'Server = http://repo.archlinux.fr/$arch'
 echo ' ') | sudo tee -a /etc/pacman.conf >/dev/null

Eğer eklerseniz -eiçin echo(ve destekleri POSIX olmayan uzatma o bir kabuk kullanıyorsanız), kullanmakta dize doğrudan yeni satır gömebilirsiniz \n:

# NON-POSIX - NOT RECOMMENDED
echo -e '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | 
  sudo tee -a /etc/pacman.conf >/dev/null

Ancak yukarıda da söylediği gibi, bu POSIX tarafından belirtilen davranış değildir; Kabuğunuz sadece bir değişmez değeri ve -eardından bir dizi değişmez \ns içeren bir dizeyi yankılayabilir . Bunu yapmanın POSIX yolu, printfyerine kullanmaktır echo; otomatik olarak argümanına yaptığı gibi davranır echo -e, ancak otomatik olarak sonuna bir satırsonu eklemez, bu yüzden \noraya da bir fazladan yapıştırmanız gerekir :

printf '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n \n' | 
  sudo tee -a /etc/pacman.conf >/dev/null

Bu çözümlerden herhangi birinde, bir argüman dizesi olarak komutun aldığı şey iki karakterli diziyi içerir \nve bunu yeni satıra çevirmek komut programının kendisine (içindeki kod printfveya echo) bağlıdır. Birçok modern kabukları, sen ANSI tırnak kullanma seçeneği $'... 'gibi dizileri çevirmek hangi \niçine literal komut programı hiç dize görmeden satırbaşıyla. Bu, bu tür dizelerin herhangi bir komutla çalıştığı anlamına gelir, düz eski -e-siz dahil echo:

echo $'[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | 
  sudo tee -a /etc/pacman.conf >/dev/null

Ancak, daha taşınabilir olsalar da echo -e, ANSI alıntıları hala POSIX olmayan bir uzantıdır.

Ve yine, bunların hepsi seçenek olsa da, tee <<EOFyukarıdaki düz çözümü tercih ediyorum .


İlginç! Dosyayı / dev / null dizinine eklemenin nedenini açıklayan bir not ekleyebilir misiniz?
2014

sudo bash -c 'foo >/some/file'osx benim için çalışıyor :-)
kayochin

Bu yanıtı tercih ediyorum çünkü çok satırlı metinle çalışıyor. cat <<EOF | sudo tee -a /some/file > /dev/null ...
ltvan

Gereksiz bir catsüreç eklemeniz dışında, bu gerçekten son cevabım . :)
Mark Reed

17

http://www.innovationsts.com/blog/?p=2758

Yukarıdaki talimatlar o kadar net olmadığından, o blog gönderisindeki talimatları kullanıyorum. Örneklerle, ne yapmanız gerektiğini görmek daha kolay.

$ sudo cat /root/example.txt | gzip> /root/example.gz
-bash: /root/example.gz: İzin reddedildi

Hataya neden olan kanaldaki ikinci komutun (gzip komutu) olduğuna dikkat edin. -C seçeneği ile bash kullanma tekniğimiz burada devreye giriyor.

$ sudo bash -c 'kedi / kök/örnek.txt | gzip> /root/example.gz '
$ sudo ls /root/example.gz
/root/example.gz

Ls komutunun çıktısından sıkıştırılmış dosya oluşturma işleminin başarılı olduğunu görebiliriz.

İkinci yöntem, bash'a bir komut dizesi iletmemiz açısından ilkine benzer, ancak bunu sudo aracılığıyla bir ardışık düzen içinde yapıyoruz.

$ sudo rm /root/example.gz
$ echo "cat /root/example.txt | gzip> /root/example.gz" | sudo bash
$ sudo ls /root/example.gz
/root/example.gz


1
Bu kadar basit bir komut için, bash yerine sh kullanmak biraz daha iyi olabilir. Örneğin sudo sh -c 'kedi /root/example.txt | gzip> /root/example.gz '. Ama aksi takdirde, iyi açıklamalar +1.
bryce


1

ADIM 1 bir bash dosyasında ( write_pacman.sh) bir işlev oluşturun

#!/bin/bash

function write_pacman {
 tee -a /etc/pacman.conf > /dev/null << 'EOF'
  [archlinuxfr]
  Server = http://repo.archlinux.fr/\$arch
EOF
}

'EOF'$archdeğişkeni yorumlamayacaktır .

STE2 kaynak bash dosyası

$ source write_pacman.sh

ADIM 3 işlevi yürütmek

$ write_pacman

EOF'daki alıntı ne için?
bilabila

0

dosyaları ekle (sudo cat):

cat <origin-file> | sudo tee -a <target-file>

dosyaya yankı ekle (sudo echo):

echo <origin> | sudo tee -a <target-file>

(EKSTRA) çıktıyı dikkate almayın:

echo >origin> | sudo tee -a <target-file> >/dev/null
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.