Próbuję zautomatyzować dodawanie źródła repozytorium w pliku pacman.conf mojego arch, ale używając echo
polecenia w moim skrypcie powłoki. Jednak kończy się to niepowodzeniem: -
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
Jeśli wprowadzę zmiany w /etc/pacman.conf ręcznie za pomocą vima, wykonując
sudo vim /etc/pacman.conf
i wychodząc z vima :wq
, wszystko działa dobrze, a mój pacman.conf został ręcznie zaktualizowany bez narzekań „Odmowa uprawnień”.
Dlaczego tak jest? A jak dostanę się sudo echo
do pracy? (btw, próbowałem sudo cat
też użyć, ale to się nie udało z odmową uprawnień)
Odpowiedzi:
Problem polega na tym, że przekierowanie jest przetwarzane przez oryginalną powłokę, a nie przez
sudo
. Muszle nie są w stanie czytać w myślach i nie wiedzą, że ten konkretny>>
jest przeznaczony dla niego,sudo
a nie dla niego.Musisz:
sudo)
sudo -s
(abysudo
użyć powłoki do przetworzenia cytowanego przekierowania).źródło
sudo -s
(2), echo "# test" >> /etc/pacman.conf działa. Ale czy można to wykonać w jednej linii?sudo -s 'echo "# test" >>/etc/pacman.conf'
jest tym, co starałem się wam przekazać.sudo -s 'echo "# test" >> /etc/pacman.conf' /bin/bash: echo "# test" >> /etc/pacman.conf: No such file or directory
dlatego później wypróbowałem dwuetapowy proces ręczny.echo 'echo "# test" >> /etc/pacman.conf' | sudo -s
sudo
wyłączaniu konfiguracji-s
? visudo?Jak wyjaśnił @geekosaur, powłoka dokonuje przekierowania przed uruchomieniem polecenia. Kiedy wpiszesz to:
Twój bieżący proces powłoki tworzy kopię samego siebie, która najpierw próbuje otworzyć się
/some/file
do zapisu, następnie ustawia ten deskryptor pliku jako standardowe wyjście, a dopiero potem wykonujesudo
.Jeśli masz pozwolenie (konfiguracje sudoer często uniemożliwiają uruchamianie powłok), możesz zrobić coś takiego:
sudo bash -c 'foo >/some/file'
Ale ogólnie uważam, że dobrym rozwiązaniem jest użycie
| sudo tee
zamiast>
i| sudo tee -a
zamiast>>
. Jest to szczególnie przydatne, jeśli przekierowanie jest jedynym powodem, którego potrzebujęsudo
w pierwszej kolejności; w końcu niepotrzebne uruchamianie procesów jako root jest właśnie tym, czegosudo
należy unikać. A bieganieecho
jako root jest po prostu głupie.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
Dodałem
> /dev/null
na końcu, ponieważtee
wysyła swoje dane wyjściowe zarówno do wymienionego pliku, jak i na swoje własne standardowe wyjście, i nie muszę go widzieć na moim terminalu. (tee
Polecenie działa jak łącznik "T" w fizycznym potoku, skąd bierze swoją nazwę.) I przełączyłem się na pojedyncze cudzysłowy ('
...'
) zamiast podwójnych ("
..."
), więc wszystko jest dosłowne i ja nie trzeba było umieszczać odwrotnego ukośnika przed$
in$arch
. (Bez cudzysłowów lub ukośnika odwrotnego$arch
zostałby zastąpiony wartością parametru powłokiarch
, który prawdopodobnie nie istnieje, w takim przypadku$arch
jest zastępowany przez nic i po prostu znika).To zajmuje się zapisywaniem do plików jako root przy użyciu
sudo
. Teraz długa dygresja na temat sposobów wyprowadzania tekstu zawierającego znak nowej linii w skrypcie powłoki. :)Dla BLUF, jak mówią, moim preferowanym rozwiązaniem byłoby po prostu wprowadzenie dokumentu tutaj do powyższego
sudo tee
polecenia; wtedy nie ma potrzebycat
lubecho
lubprintf
lub innych komend w ogóle. Pojedyncze cudzysłowy przeniosły się do wprowadzenia wartowniczego<<'EOF'
, ale tam mają ten sam efekt: treść jest traktowana jako tekst dosłowny, więc$arch
pozostaje w spokoju:sudo tee -a /etc/pacman.conf >/dev/null <<'EOF' [archlinuxfr] Server = http://repo.archlinux.fr/$arch EOF
Ale chociaż tak bym to zrobił, są alternatywy. Tu jest kilka:
Możesz trzymać się jednego w
echo
każdym wierszu, ale zgrupować je wszystkie razem w podpowłoce, więc wystarczy dołączyć do pliku tylko raz:(echo '[archlinuxfr]' echo 'Server = http://repo.archlinux.fr/$arch' echo ' ') | sudo tee -a /etc/pacman.conf >/dev/null
Jeśli dodasz
-e
doecho
(i używasz powłoki, która obsługuje to rozszerzenie inne niż POSIX), możesz osadzić znaki nowej linii bezpośrednio w ciągu za pomocą\n
:# NON-POSIX - NOT RECOMMENDED echo -e '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | sudo tee -a /etc/pacman.conf >/dev/null
Ale jak powiedziano powyżej, nie jest to zachowanie określone w standardzie POSIX; Twoja powłoka może zamiast tego powtórzyć literał,
-e
a po nim ciąg znaków zawierający kilka literałów\n
s. Sposób zgodny z POSIX polega na używaniuprintf
zamiastecho
; automatycznie traktuje swój argument tak jakecho -e
robi, ale nie dodaje automatycznie nowej linii na końcu, więc musisz też wstawić\n
tam dodatkowy :printf '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n \n' | sudo tee -a /etc/pacman.conf >/dev/null
W przypadku każdego z tych rozwiązań to, co polecenie otrzymuje jako ciąg argumentu, zawiera sekwencję dwóch znaków
\n
, a sam program poleceń (kod wewnątrzprintf
lubecho
) musi przetłumaczyć to na znak nowej linii. W wielu współczesnych muszli, masz możliwość korzystania cytaty ANSI$'
...'
, co przełoży sekwencje jak\n
język dosłownych nowej linii zanim program komenda kiedykolwiek widzi ciąg. Oznacza to, że takie ciągi działają z każdym poleceniem, w tym zwykłym starym--e
bezecho
:echo $'[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | sudo tee -a /etc/pacman.conf >/dev/null
Ale, choć bardziej przenośne niż
echo -e
, cudzysłowy ANSI nadal są rozszerzeniem innym niż POSIX.I znowu, chociaż to wszystkie opcje, wolę proste
tee <<EOF
rozwiązanie powyżej.źródło
sudo bash -c 'foo >/some/file'
działa u mnie na osx :-)cat <<EOF | sudo tee -a /some/file > /dev/null ...
cat
proces. :)http://www.innovationsts.com/blog/?p=2758
Ponieważ powyższe instrukcje nie są zbyt jasne, korzystam z instrukcji z tego wpisu na blogu. Z przykładami, aby łatwiej było zobaczyć, co musisz zrobić.
Zwróć uwagę, że to drugie polecenie (polecenie gzip) w potoku powoduje błąd. W tym miejscu pojawia się nasza technika używania basha z opcją -c.
Na podstawie danych wyjściowych polecenia ls widzimy, że utworzenie skompresowanego pliku powiodło się.
Druga metoda jest podobna do pierwszej, ponieważ przekazujemy polecenie do bash, ale robimy to w potoku za pośrednictwem sudo.
źródło
sudo bash -c 'echo "[archlinuxfr]" >> /etc/pacman.conf'
źródło
KROK 1 utwórz funkcję w pliku bash (
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'
nie będzie interpretować$arch
zmiennej.Plik źródłowy bash STE2
$ source write_pacman.sh
KROK 3 wykonaj funkcję
źródło
dołącz pliki (sudo cat):
dołącz echo do pliku (sudo echo):
echo <origin> | sudo tee -a <target-file>
(EXTRA) pomijają wynik:
echo >origin> | sudo tee -a <target-file> >/dev/null
źródło