Как использовать sudo для перенаправления вывода в местоположение, на которое у меня нет разрешения на запись?

Мне предоставлен sudo-доступ в одном из наших оконных блоков RedHat для разработки, и мне кажется, что мне довольно часто приходится перенаправлять вывод на место, в котором я обычно не имею доступа на запись.

Проблема в том, что этот надуманный пример не работает:

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

Я просто получаю ответ:

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

Как я могу заставить это работать?

Ответ 1

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

Существует несколько решений:

  • Запустите оболочку с sudo и дайте ей команду с помощью опции -c:

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

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

    Запустите sudo ls.sh. См. Steve Bennett answer, если вы не хотите создавать временный файл.

  • Запустите оболочку с sudo -s, затем запустите свои команды:

    [[email protected]]$ sudo -s
    [[email protected]]# ls -hal /root/ > /root/test.out
    [[email protected]]# ^D
    [[email protected]]$
    
  • Используйте sudo tee (если вам нужно много избегать при использовании опции -c):

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

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

Спасибо, Jd, Адам Дж. Форстер и Johnathan для второго, третьего и четвертого решений.

Ответ 2

Кто-то здесь только что предложил sudoing tee:

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

Это также можно использовать для перенаправления любой команды в каталог, к которому у вас нет доступа. Это работает, потому что программа tee эффективно представляет собой программу "echo to file", а перенаправление на /dev/null - это также остановка ее вывода на экран, чтобы она оставалась такой же, как и исходный надуманный пример выше.

Ответ 3

Трюк, который я понял, был

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

Ответ 4

Проблема в том, что команда запускается под 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"
    

Ответ 5

Еще одна вариация темы:

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

Или, конечно же:

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

У них есть (крошечное) преимущество, что вам не нужно запоминать какие-либо аргументы для sudo или sh/bash

Ответ 6

Уточнение вопроса о том, почему предпочтительнее вариант тройника

Предполагая, что у вас есть соответствующее разрешение для выполнения команды, которая создает вывод, если вы передаете вывод вашей команды в tee, вам нужно только поднять тэли с помощью sudo и direct 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

В каждом из этих примеров вы принимаете вывод не-привилегированной команды и записываете в файл, который обычно записывается только root, что является источником вашего вопроса.

Это хорошая идея сделать это так, потому что команда, которая генерирует вывод, не выполняется с повышенными привилегиями. Здесь не имеет значения echo, но когда исходная команда является script, которую вы не полностью доверяете, это имеет решающее значение.

Обратите внимание, что вы можете использовать параметр -a для tee, чтобы добавить append (например, >>) в целевой файл, а не перезаписывать его (например, >).

Ответ 7

Сделать sudo запустить оболочку, например:

sudo sh -c "echo foo > ~root/out"

Ответ 8

Как я могу решить эту проблему:

Если вам нужно написать/заменить файл:

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

Если вам нужно добавить файл:

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

Ответ 9

Как насчет написания script?

Имя файла: myscript

#!/bin/sh

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

# end script

Затем используйте sudo для запуска script:

sudo ./myscript

Ответ 10

Я бы сделал это следующим образом:

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

Ответ 11

Всякий раз, когда мне приходится делать что-то подобное, я просто становлюсь root:

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

Это, вероятно, не самый лучший способ, но он работает.

Ответ 12

Не нужно бить мертвой лошади, но здесь слишком много ответов, которые используют tee, что означает, что вам нужно перенаправить stdout в /dev/null, если вы не хотите видеть копию на экране. Более простым решением является просто использовать cat следующим образом:

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

Обратите внимание, как перенаправление помещается внутри кавычек, чтобы оно оценивалось оболочкой, запущенной sudo, а не той, которая ее запускала.

Ответ 13

Это основано на ответе с участием 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 "[email protected]" ; do
    if [ ${arg#/dev/} != ${arg} ] ; then
        echo "Found dangerous argument ‘$arg. Will exit."
        exit 2
    fi
done
sudo tee "[email protected]" > /dev/null

Как показано в коде " ИСПОЛЬЗОВАНИЕ" в коде, все, что вам нужно сделать, - это передать выходные данные в этот сценарий, за которым следует желаемое имя доступного суперпользователя -a, и при необходимости он автоматически запросит ваш пароль (поскольку он включает sudo).

echo test | suwrite /root/test.txt

Обратите внимание, что, поскольку это простая оболочка для tee, она также принимает опцию tee -a для добавления, а также поддерживает запись в несколько файлов одновременно.

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

Он также имеет некоторую упрощенную защиту от записи в /dev/ devices, о чем упоминалось в одном из комментариев на этой странице.

Ответ 14

Возможно, вам предоставили доступ к sudo только для некоторых программ/путей? Тогда нет способа сделать то, что вы хотите. (если вы его не взломаете)

Если это не так, возможно, вы можете написать bash script:

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

Нажмите ctrl + d:

chmod a+x myscript.sh
sudo myscript.sh

Надеюсь, что это поможет.

Ответ 15

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