Как объяснил @geekosaur, оболочка выполняет перенаправление перед запуском команды. Когда вы набираете это:
sudo foo >/some/file
Текущий процесс оболочки создает свою копию, которая сначала пытается открыть /some/file
для записи, затем делает этот файловый дескриптор своим стандартным выводом и только после этого выполняется sudo
.
Если вам разрешено (конфигурации sudoer часто не позволяют запускать оболочки), вы можете сделать что-то вроде этого:
sudo bash -c 'foo >/some/file'
Но я считаю, что в целом хорошее решение - использовать | sudo tee
вместо >
и | sudo tee -a
вместо >>
. Это особенно полезно, если перенаправление - единственная причина, по которой мне sudo
в первую очередь нужно ; в конце концов, ненужный запуск процессов от имени root - это именно то, чего sudo
нужно избегать. А запускать echo
под root просто глупо.
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
отправляет свой вывод как в названный файл, так и в собственный стандартный вывод, и мне не нужно видеть его на моем терминале. (Команда tee
действует как Т-образный соединитель в физическом конвейере, отсюда и получила свое название.) И я переключился на одинарные кавычки ( '
... '
) вместо двойных ( "
... "
), так что все было буквально, и я не нужно ставить обратную косую черту перед $
in $arch
. (Без кавычек или обратной косой черты он $arch
будет заменен значением параметра оболочки arch
, который, вероятно, не существует, и в этом случае $arch
заменяется ничем и просто исчезает.)
Таким образом, мы позаботимся о записи файлов с правами root с использованием sudo
. Теперь продолжительное отступление о способах вывода текста, содержащего новую строку, в сценарии оболочки. :)
Что касается BLUF, то, как они говорят, моим предпочтительным решением было бы просто передать здесь-документ в указанную выше sudo tee
команду; то нет никакой необходимости cat
или echo
или printf
или каких - либо других команд на всех. Одиночные кавычки переместились во вводную часть дозорного <<'EOF'
, но они имеют тот же эффект: тело обрабатывается как буквальный текст, поэтому $arch
остается в покое:
sudo tee -a /etc/pacman.conf >/dev/null <<'EOF'
[archlinuxfr]
Server = http://repo.archlinux.fr/$arch
EOF
Но пока я бы так поступил, есть альтернативы. Вот несколько:
Вы можете использовать по одному в echo
каждой строке, но сгруппировать их все вместе в подоболочке, поэтому вам нужно добавить в файл только один раз:
(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
s. В 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
решение, указанное выше.