Почему sudo cat дает разрешение на отказ, но sudo vim отлично работает?

Я пытаюсь автоматизировать добавление источника репозитория в свой файл arch pacman.conf, но используя команду echo в моей оболочке script. Однако это не так: -

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 вручную, используя vim, выполняя

sudo vim /etc/pacman.conf

и quiting vim с :wq, все работает отлично, и мой pacman.conf был обновлен вручную без жалоб на отказ от прав.

Почему это так? И как мне получить sudo echo для работы? (Кстати, я пробовал использовать sudo cat тоже, но это не удалось с Разрешением также отказано)

Ответ 1

Проблема заключается в том, что перенаправление обрабатывается вашей исходной оболочкой, а не sudo. Корпуса не способны читать мысли и не знают, что этот >> предназначен для sudo, а не для него.

Вам необходимо:

  • укажите перенаправление (поэтому он передается на sudo)
  • и использовать sudo -s (так что sudo использует оболочку для обработки цитированного перенаправления.)

Ответ 2

Как пояснил @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 действует как "T" -коннектор в физическом конвейере, где и получает свое имя.) И я переключился на одиночные кавычки ('... ') вместо двухлокальных (... "), так что все буквально, и мне не нужно было обращать обратную косу перед $ в $arch.

Таким образом, для записи в файлы с правами root используется sudo. Теперь для длинного отступления о способах вывода текста, содержащего новую строку, в оболочке script.:)

Во-первых, вы можете просто сгруппировать все echo вместе в подоболочке, поэтому вам нужно только выполнить перенаправление один раз:

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

Или используйте printf вместо echo, поэтому вы можете вставлять новые строки непосредственно в строку с помощью \n:

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

В bash вы можете получить тот же результат с помощью echo -e:

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

Но большинство оболочек будут выводить -e при попытке, поэтому не рекомендуется.

При использовании printf и echo -e то, что команда получает как строку аргумента, содержит aa буквальный обратный слэш, за которым следует буква N, куда вы введете \n, и до самой командной программы (код внутри printf или echo), чтобы перевести это в новую строку. Во многих современных оболочках у вас есть возможность использовать цитаты ANSI $'... ', которые будут транслировать последовательности, такие как \n, в литеральные символы новой строки, прежде чем командная программа когда-либо увидит эту строку, что означает, что такие строки работают с любыми команда:

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

Но, хотя более портативный, чем echo -e, кавычки ANSI по-прежнему являются не-POSIX-расширением.

Мой предпочтительный способ сделать это - использовать здесь документ и полностью исключить необходимость echo или printf:

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

EOF

Ответ 3

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

Поскольку инструкции не так ясны выше, я использую инструкции из этого сообщения в блоге. С примерами, чтобы было легче увидеть, что вам нужно сделать.

$sudo cat/root/example.txt | gzip > /root/example.gz
- bash:/root/example.gz: запрещен отказ

Обратите внимание, что вторая команда (команда gzip) в конвейере вызывает ошибку. Вот где наша техника использования bash с опцией -c.

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

Мы можем видеть, что на выходе команды ls создается сжатое создание файла.

Второй метод похож на первый в том, что передал командную строку в bash, но делал это в конвейере через sudo.

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

Ответ 4

sudo bash -c 'echo "[archlinuxfr]" >> /etc/pacman.conf'

Ответ 5

ШАГ 1 создать функцию в файле bash

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

'EOF' не будет интерпретировать переменную $arch.

STE2 исходный bash файл

$ source write_pacman.sh

STEP 3 выполнить функцию

$ write_pacman