Jak wyjaśnił @geekosaur, powłoka dokonuje przekierowania przed uruchomieniem polecenia. Kiedy wpiszesz to:
sudo foo >/some/file
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 wykonuje sudo
.
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, czego sudo
należy unikać. A bieganie echo
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łoki arch
, 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 potrzeby cat
lub echo
lub printf
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
do echo
(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
:
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żywaniu printf
zamiast echo
; automatycznie traktuje swój argument tak jak echo -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ątrz printf
lub echo
) 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
bez echo
:
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.