it-swarm.com.de

Warum gibt Sudo Katze eine verweigerte Erlaubnis, aber Sudo vim funktioniert gut?

Ich versuche, das Hinzufügen einer Repository-Quelle in die pacman.conf-Datei meines Arch zu automatisieren, verwende jedoch den Befehl echo in meinem Shell-Skript. Es schlägt jedoch folgendermaßen fehl:

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

Wenn ich mit vim manuell Änderungen an /etc/pacman.conf vornehme, mache ich Folgendes

Sudo vim /etc/pacman.conf

und beenden Sie vim mit :wq, alles funktioniert einwandfrei und meine pacman.conf wurde manuell aktualisiert, ohne dass "Erlaubnis verweigert" -Beschwerden vorlagen.

Warum ist das so? Und wie bekomme ich Sudo echo arbeiten? (Übrigens habe ich versucht, Sudo cat auch, aber das scheiterte auch mit verweigerter Erlaubnis)

75
Calvin Cheng

Das Problem ist, dass die Umleitung von Ihrer ursprünglichen Shell verarbeitet wird, nicht von Sudo. Shells können keine Gedanken lesen und wissen nicht, dass dieses bestimmte >> Für das Sudo und nicht dafür gedacht ist.

Du brauchst:

  1. zitiere die Weiterleitung (so wird sie an Sudo) weitergeleitet)
  2. nd verwende Sudo -s (so dass Sudo eine Shell verwendet, um die angegebene Umleitung zu verarbeiten.)
42
geekosaur

Wie @geekosaur erklärte, führt die Shell die Umleitung durch, bevor der Befehl ausgeführt wird. Wenn Sie dies eingeben:

Sudo foo >/some/file

Ihr aktueller Shell-Prozess erstellt eine Kopie von sich selbst, die zuerst versucht, /some/file Zum Schreiben zu öffnen, diesen Dateideskriptor dann zur Standardausgabe macht und erst dann Sudo ausführt.

Wenn Sie dazu berechtigt sind (Sudoer-Konfigurationen schließen häufig das Ausführen von Shells aus), können Sie Folgendes tun:

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

Aber ich finde eine gute Lösung im Allgemeinen, | Sudo tee Anstelle von > Und | Sudo tee -a Anstelle von >> Zu verwenden. Dies ist besonders nützlich, wenn die Umleitung der einzige Grund ist, warum ich Sudo überhaupt brauche. Schließlich ist es genau das, was Sudo geschaffen hat, um unnötig laufende Prozesse als root zu vermeiden. Und echo als root auszuführen ist einfach albern.

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

Ich habe > /dev/null Am Ende hinzugefügt, weil tee seine Ausgabe an beide die genannte Datei nd seine eigene Standardausgabe sendet und ich nicht ' Ich muss es nicht auf meinem Terminal sehen. (Der Befehl tee verhält sich wie ein "T" -Anschluss in einer physischen Pipeline. Dort erhält er seinen Namen.) Und ich habe auf einfache Anführungszeichen umgestellt (' ... ') anstelle von Doubles (" ... "), so dass alles wörtlich ist und ich keinen Backslash vor dem $ in $Arch.

Damit ist das Schreiben in Dateien als root mit Sudo erledigt. Nun zu einem ausführlichen Exkurs über die Ausgabe von Newline-haltigem Text in einem Shell-Skript. :)

Zunächst können Sie alle echo in einer Subshell zusammenfassen, sodass Sie die Umleitung nur einmal durchführen müssen:

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

Oder verwenden Sie printf anstelle von echo, damit Sie Zeilenumbrüche mit \n Direkt in den String einbetten können:

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

In bash können Sie dasselbe Ergebnis mit echo -e Erhalten:

# BASH ONLY - NOT RECOMMENDED
echo -e '[archlinuxfr]\nServer = http://repo.archlinux.fr/$Arch\n ' | 
  Sudo tee -a /etc/pacman.conf >/dev/null

Aber die meisten Shells geben nur den -e Aus, wenn Sie das versuchen, es wird also nicht empfohlen.

Mit printf und echo -e Enthält das, was der Befehl als Argumentzeichenfolge erhält, einen wörtlichen Backslash, gefolgt von einem wörtlichen N, wo immer Sie \n Eingeben, und es liegt am Befehlsprogramm selbst (der Code in printf oder echo), um dies in eine neue Zeile zu übersetzen. In vielen modernen Shells können Sie ANSI-Anführungszeichen $' ... ' Verwenden, um Sequenzen wie \n In wörtliche Zeilenumbrüche zu übersetzen Bevor das Befehlsprogramm den String sieht, funktionieren solche Strings mit jedem beliebigen Befehl:

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

ANSI-Anführungszeichen sind zwar portabler als echo -e, Aber immer noch keine POSIX-Erweiterung.

Mein bevorzugter Weg, dies zu tun, wäre, ein Here-Dokument zu verwenden und die Notwendigkeit für echo oder printf gänzlich zu vermeiden:

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

EOF
113
Mark Reed

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

Da die Anweisungen oben nicht so klar sind, verwende ich die Anweisungen aus diesem Blog-Beitrag. Anhand von Beispielen ist es einfacher zu erkennen, was Sie tun müssen.

$ Sudo cat /root/example.txt | gzip> /root/example.gz
- bash: /root/example.gz: Erlaubnis verweigert

Beachten Sie, dass es der zweite Befehl (der gzip-Befehl) in der Pipeline ist, der den Fehler verursacht. Hier kommt unsere Technik zum Verwenden von bash mit der Option -c ins Spiel.

$ Sudo bash -c 'cat /root/example.txt | gzip> /root/example.gz '
$ Sudo ls /root/example.gz
/root/example.gz

Aus der Ausgabe des Befehls ls geht hervor, dass die Erstellung der komprimierten Datei erfolgreich war.

Die zweite Methode ähnelt der ersten, da wir eine Befehlszeichenfolge an bash übergeben, dies jedoch in einer Pipeline über Sudo tun.

$ Sudo rm /root/example.gz
$ echo "cat /root/example.txt | gzip> /root/example.gz" | Sudo-Bash
$ Sudo ls /root/example.gz
/root/example.gz

17
nelaaro
Sudo bash -c 'echo "[archlinuxfr]" >> /etc/pacman.conf'
6
Peyman Mahdian

SCHRITT 1 eine Funktion in einer Bash-Datei erstellen (write_pacman.sh)

#!/bin/bash

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

'EOF' Interpretiert die Variable $Arch Nicht.

STE2 Quell-Bash-Datei

$ source write_pacman.sh

SCHRITT Funktion ausführen

$ write_pacman
1
prayagupd