Як я можу використовувати sudo для перенаправлення виводу на місце, до якого я не маю дозволу писати?


881

Мені було надано доступ до sudo на одній з розроблених нами Linux-ящиків RedHat, і, здається, мені досить часто потрібно перенаправляти вихід на місце, до якого зазвичай не мають доступу для запису.

Проблема в тому, що цей надуманий приклад не працює:

sudo ls -hal /root/ > /root/test.out

Я просто отримую відповідь:

-bash: /root/test.out: Permission denied

Як я можу змусити це працювати?


1
використовувати ім'я файлу chmod u + w
Szabolcs Dombi

@DombiSzabolcs Ви пропонуєте мені спершу створити файл як sudo, а потім дати собі дозвіл? Гарна ідея.
Джонатан

У багатьох ситуаціях ви опиняєтесь тут, тому що ви запитували "чому мені відмовляють у дозволі?" Іноді відповідь полягає в тому, що вам потрібно створити файл як root(в такому випадку переходити до читання відповідей), але дуже часто вам просто потрібно створити файл десь в іншому місці, як ви самі.
трійка

1
Після боротьби з цими відповідями я, нарешті, вирішую перенаправляти на тимчасовий файл і судо переміщувати його до місця призначення.
TingQian LI

Відповіді:


1232

Ваша команда не працює, оскільки перенаправлення виконує ваша оболонка, яка не має дозволу писати /root/test.out. Перенаправлення виводу не здійснюється sudo.

Є кілька рішень:

  • Запустіть оболонку з sudo і дайте команду їй за допомогою -cпараметра:

    sudo sh -c 'ls -hal /root/ > /root/test.out'
    
  • Створіть сценарій зі своїми командами та запустіть цей сценарій із sudo:

    #!/bin/sh
    ls -hal /root/ > /root/test.out
    

    Біжи sudo ls.sh. Див Стіва Беннетта відповідь , якщо ви не хочете , щоб створити тимчасовий файл.

  • Запустіть оболонку, а sudo -sпотім запустіть ваші команди:

    [nobody@so]$ sudo -s
    [root@so]# ls -hal /root/ > /root/test.out
    [root@so]# ^D
    [nobody@so]$
    
  • Використовуйте sudo tee(якщо вам доведеться багато втекти при використанні -cопції):

    sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null
    

    Переспрямування на /dev/nullпотрібне, щоб зупинити вихід трійника на екран. Щоб додати замість перезаписування вихідного файлу ( >>), використовуйте tee -aабо tee --append(останній характерний для GNU coreutils ).

Дякуємо Jd , Адаму Дж. Форстеру та Джонатану за друге, третє та четверте рішення.


1
Там відмінний відповідь , який говорить вам , як перенаправити STDERR і STDOUT окремо тут: stackoverflow.com/questions/692000 / ... ... в основномуperl -e 'print "STDIN\n"; print STDERR "STDERR\n"; ' > >( tee stdout.log ) 2> >( tee stderr.log >&2 )
errant.info

2
Ви хочете зробити "sudo -E ...", щоб використовувати змінні в команді, що захищається (наприклад, наприклад, у сценарії).
Урхіксидур

3
Перенаправлення виходу трійника на / dev / null, мабуть, не потрібне у багатьох випадках, коли повторення виводу на екран нешкідливо. Наприклад, при роботі лише з виведенням звичайних команд або вмістом невеликих текстових файлів.
thomasrutter

105

Хтось тут щойно запропонував надіти трійник:

sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null

Це також може бути використане для переадресації будь-якої команди до каталогу, до якого ви не маєте доступу. Це працює тому, що програма трійника фактично є програмою «відлуння до файлу», а переадресація на / dev / null полягає у тому, щоб зупинити її також на вихід на екран, щоб зберегти його таким же, як оригінальний надуманий вище приклад.


5
У багатьох випадках, а саме, якщо звичайний користувач має права на виконання команди і "тільки" не може записати в потрібний вихідний файл, перший sudo(тобто для самої команди) може бути опущений
Хаген фон Ейтцен

81

Трюк, який я зрозумів сам, був

sudo ls -hal /root/ | sudo dd of=/root/test.out

16
sudo ddкраще, ніж наведені sudo tee /root/file > /dev/nullвище приклади!
kristianlm

14
dd - не дивна незрозуміла команда. Він використовується, коли потрібно копіювати велику кількість даних за допомогою буферизації між двома блоковими пристроями. Синтаксис насправді досить простий, ddце ім'я команди, of=/root/test.outце аргумент, який розповідає, ddщо таке вихідні файли.
rhlee

14
@steve Все "незрозуміло", поки ви не дізнаєтеся, що це таке. ofозначає вихідний файл і ddє дуже популярним інструментом, який використовується як в Linux, так і в OSX (в основному для запису зображень на диски). Це точно акуратний трюк.
blockloop

12
ddмабуть, не менш корисний, як teeтут. В обох випадках ви використовуєте загальну, добре відому команду для тієї мети, яка, хоча і трохи відрізняється від її початкової мети, все-таки добре відома і добре задокументована. Хоча ddце добре копіювати величезну кількість даних, вона не всмоктується з невеликими обсягами. Тут є користь у тому, що не повторюється вихід до стандартного випуску.
thomasrutter

26
Щоразу, коли ви вводите слова sudo ddпоруч, хочете зробити дуже, дуже впевнені, що наведені нижче аргументи є правильними (особливо з урахуванням його нестандартного синтаксису). Вони ні за що не називають його "знищувачем диска" ...
ali_m

45

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

sudo command > /some/file.log
`-----v-----'`-------v-------'
   command       redirection

Звичайні способи їх обходу є:

  • Оберніть команди в сценарій, який ви викликаєте під sudo.

    Якщо команди та / або файл журналу змінюються, ви можете змусити скрипт приймати їх як аргументи. Наприклад:

    sudo log_script command /log/file.txt
    
  • Викличте оболонку та передайте командний рядок як параметр із -c

    Це особливо корисно для одноразових складних команд. Наприклад:

    sudo bash -c "{ command1 arg; command2 arg; } > /log/file.txt"
    

23

Ще одна варіація теми:

sudo bash <<EOF
ls -hal /root/ > /root/test.out
EOF

Або звичайно:

echo 'ls -hal /root/ > /root/test.out' | sudo bash

Вони мають (крихітний) перевага , що вам не потрібно запам'ятовувати які - які аргументи sudoабо sh/bash


18

Трохи уточнити, чому варіант трійника є кращим

Якщо припустити, що у вас є відповідний дозвіл на виконання команди, яка створює вихід, якщо ви передаєте висновок вашої команди в tee, вам потрібно лише підняти privledges tee за допомогою sudo і прямо tee, щоб написати (або додати) до відповідного файлу.

у прикладі, наведеному у питанні, що означатиме:

ls -hal /root/ | sudo tee /root/test.out

ще кілька практичних прикладів:

# kill off one source of annoying advertisements
echo 127.0.0.1 ad.doubleclick.net | sudo tee -a /etc/hosts

# configure eth4 to come up on boot, set IP and netmask (centos 6.4)
echo -e "ONBOOT=\"YES\"\nIPADDR=10.42.84.168\nPREFIX=24" | sudo tee -a /etc/sysconfig/network-scripts/ifcfg-eth4

У кожному з цих прикладів ви берете висновок непривілейованої команди та записуєте у файл, який, як правило, записується лише коренем, що є джерелом вашого питання.

Це добре робити так, оскільки команда, яка генерує результат, не виконується з підвищеними правами. Це, мабуть, не має значення, echoале коли команда-джерело - це сценарій, якому ви повністю не довіряєте, це дуже важливо.

Зауважте, що ви можете використовувати опцію -a tee, щоб додати додаток (як >>) до цільового файлу, а не перезаписати його (як >).


Вибачте, js3, але це вже було запропоновано (ще в 2008 році), і він знаходиться у другій найвищій відповіді: stackoverflow.com/a/82553/6910
Джонатан

2
Ти маєш рацію, Джонатане, я оновлю свою відповідь, щоб розкрити причини, чому це кращий варіант. Дякуємо за корисні відгуки.
jg3


11

Я пішов би з цього питання:

Якщо вам потрібно написати / замінити файл:

echo "some text" | sudo tee /path/to/file

Якщо вам потрібно додати файл:

echo "some text" | sudo tee -a /path/to/file

1
Чим це суттєво відрізняється від відповідей вище?
Джонатан

2
Це не «суттєво відрізняється», але це пояснює відмінне використання між заміною та додаванням до файлу.
jamadagni

1
Це відповідь, яку я скопіював на свій шпаргалку.
MortimerCat

5

Як щодо написання сценарію?

Ім'я файлу: myscript

#!/bin/sh

/bin/ls -lah /root > /root/test.out

# end script

Потім використовуйте sudo для запуску сценарію:

sudo ./myscript

4

Кожного разу, коли мені потрібно щось подібне робити, я просто став корінням:

# sudo -s
# ls -hal /root/ > /root/test.out
# exit

Це, мабуть, не найкращий спосіб, але це працює.


4

Я зробив би це так:

sudo su -c 'ls -hal /root/ > /root/test.out'

2
Це насправді здається трохи чистішим, оскільки не потрібно чітко вказувати оболонку.
Стів Беннетт

1
Невеликим недоліком є ​​те, що він запускає один додатковий процес ( su): $ sudo su -c 'pstree -sp $$ >/dev/fd/1' init(1)───gnome-terminal(6880)───bash(6945)───sudo(401)───su(402)───bash(410)───pstree(411)
pabouk

3

Не хочу бити мертвого коня, але є занадто багато відповідей тут , що використання tee, що означає , що ви повинні перенаправити stdoutдо , /dev/nullякщо ви не хочете , щоб побачити копію на екрані.

Більш просте рішення - просто використовувати catтак:

sudo ls -hal /root/ | sudo bash -c "cat > /root/test.out"

Зауважте, як перенаправлення ставиться всередині лапок, щоб воно оцінювалося оболонкою, запущеною sudoзамість тієї, що працює.


Це працює просто чудово. Я не розумію, чому він мав один негативний голос. Отримано.
Теему Леїсті

4
Я думаю, що це не дуже любить, тому що це не набагато краще, ніж sudo bash -c "ls -hal /root > /root/test.out". Використання трійника уникає необхідності панцира, а кішка - ні.
Нік Руссо

2

Це ґрунтується на відповіді tee. Щоб полегшити ситуацію, я написав невеликий сценарій (я його називаю suwrite) і вклав його /usr/local/bin/з +xдозволу:

#! /bin/sh
if [ $# = 0 ] ; then
    echo "USAGE: <command writing to stdout> | suwrite [-a] <output file 1> ..." >&2
    exit 1
fi
for arg in "$@" ; do
    if [ ${arg#/dev/} != ${arg} ] ; then
        echo "Found dangerous argument ‘$arg’. Will exit."
        exit 2
    fi
done
sudo tee "$@" > /dev/null

Як показано в коді USAGE у вашому коді, все, що вам потрібно зробити, - це передати вихід на цей сценарій з подальшим необхідним ім'ям файлу, доступним для суперпользователя, і він автоматично запропонує вам пароль, якщо потрібно (оскільки він включає sudo).

echo test | suwrite /root/test.txt

Зауважте, що оскільки це проста програма для обгортки tee, вона також прийме -aможливість додавання трійника , а також підтримує запис у кілька файлів одночасно.

echo test2 | suwrite -a /root/test.txt
echo test-multi | suwrite /root/test-a.txt /root/test-b.txt

Він також має певний спрощений захист від запису на /dev/пристрої, що викликало занепокоєння, згадане в одному з коментарів на цій сторінці.


1

Можливо, вам надали доступ до судо лише до деяких програм / шляхів? Тоді немає ніякого способу зробити те, що ти хочеш. (якщо ви її якось не зламаєте)

Якщо це не так, можливо, ви можете написати bash script:

cat > myscript.sh
#!/bin/sh
ls -hal /root/ > /root/test.out 

Натисніть ctrl+ d:

chmod a+x myscript.sh
sudo myscript.sh

Сподіваюся, це допоможе.


1
sudo at now  
at> echo test > /tmp/test.out  
at> <EOT>  
job 1 at Thu Sep 21 10:49:00 2017  

1
Якщо у вас все- sudoтаки atє , це не корисно чи не потрібно. sudo sh -c 'echo test >/tmp/test.out'робить це набагато ефективніше та витонченіше (але все-таки страждає від недоліку, що ви, ймовірно, керуєте речами, rootякі не потребують цього привілею; як правило, уникайте привілейованих команд, коли можете).
трійка
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.