Чому sudo cat дає дозвіл відмовлено, але sudo vim чудово працює?


86

Я намагаюся автоматизувати додавання джерела сховища у файл pacman.conf моєї арки, але використовуючи echoкоманду в моєму сценарії оболонки. Однак це не вдається так: -

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

і після виходу з vim :wqвсе працює нормально, і мій файл pacman.conf оновлено вручну без скарг "Дозвіл відмовлено".

Чому це так? А як мені приступити sudo echoдо роботи? (до речі, я sudo catтеж намагався використовувати, але це не вдалося, оскільки дозвіл також відмовлено)


Відповіді:


51

Проблема в тому, що переспрямування обробляється вашою початковою оболонкою, а не sudo. Шкаралупи не здатні читати думки і не знають, що саме >>це призначене для, sudoа не для нього.

Тобі потрібно:

  1. цитувати перенаправлення (щоб воно передавалось sudo)
  2. і використовувати sudo -s(так що sudoвикористовує оболонку для обробки цитованого перенаправлення.)

1
Отже, роблячи це у два етапи, як це (1) sudo -s(2) відлуння "# test" >> /etc/pacman.conf працює. Але чи можна виконати це в одному рядку?
Кальвін Ченг,

15
sudo -s 'echo "# test" >>/etc/pacman.conf'це те, що я намагався донести до вас.
geekosaur

2
Насправді, я спробував це після прочитання вашої відповіді вище, але отримав дивну помилку, подібну до цієї: - sudo -s 'echo "# test" >> /etc/pacman.conf' /bin/bash: echo "# test" >> /etc/pacman.conf: No such file or directoryсаме тому згодом я спробував двохетапний ручний процес.
Calvin Cheng

16
Ах ..... остання спроба таким чином спрацювала -echo 'echo "# test" >> /etc/pacman.conf' | sudo -s
Кальвін Ченг

1
як / де я можу дізнатись про sudoвимкнення конфігурації -s? visudo?
Кальвін Ченг,

127

Як пояснив @geekosaur, оболонка робить переспрямування перед запуском команди. Коли ви вводите це:

sudo foo >/some/file

Ваш поточний процес оболонки робить копію себе, яка спочатку намагається відкрити /some/fileдля запису, потім робить цей дескриптор файлу своїм стандартним висновком і лише потім виконує sudo.

Якщо вам це дозволено (конфігурації sudoer часто виключають запущені оболонки), ви можете зробити щось подібне:

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

Але я вважаю, що загальним хорошим рішенням є використання | sudo teeзамість >і | sudo tee -aзамість >>. Це особливо корисно, якщо переспрямування є єдиною причиною, яка мені sudoперш за все потрібна ; зрештою, непотрібне запуск процесів як root - це саме те, що sudoбуло створено, щоб уникнути. А працювати echoвід імені коріння просто безглуздо.

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. (Без лапок або зворотної косої риси $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:

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

Але, як сказано вище, це не поведінка, визначена POSIX; ваша оболонка може просто повторити літерал, -eза яким слідує рядок із набором літералів \ns. 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у буквальні нові рядки, перш ніж командна програма коли-небудь побачить рядок. Це означає, що такі рядки працюють із будь-якою командою, включаючи звичайний старий -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рішенню вище.


Цікаво! Не могли б ви додати примітку, що пояснює причину того, що файл також розділений на / dev / null?
knite

sudo bash -c 'foo >/some/file'працює для мене на osx :-)
kayochin

Я віддаю перевагу цій відповіді, оскільки вона працює з багаторядковим текстом. cat <<EOF | sudo tee -a /some/file > /dev/null ...
ltvan

Це фактично моя остання відповідь, за винятком того, що ви додали сторонній catпроцес. :)
Марк Рід

17

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


1
Для такої простої команди може бути трохи краще використовувати sh замість bash. Наприклад sudo sh -c 'cat /root/example.txt | gzip> /root/example.gz '. Але інакше, хороші пояснення, +1.
bryce


1

КРОК 1 Створіть функцію у файлі 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'не буде інтерпретувати $archзмінну.

Базовий файл STE2

$ source write_pacman.sh

КРОК 3 виконує функцію

$ write_pacman

для чого потрібна котирування на EOF?
білабіла

0

додавати файли (sudo cat):

cat <origin-file> | sudo tee -a <target-file>

додати echo до файлу (sudo echo):

echo <origin> | sudo tee -a <target-file>

(EXTRA) ігнорування виходу:

echo >origin> | sudo tee -a <target-file> >/dev/null
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.