Linux: Почему sudo echo >> не работает и как писать в системные файлы правильно
Вы наверняка сталкивались с этой классической ошибкой новичка. Вы пытаетесь добавить строку в конфиг, но получаете Permission denied, даже используя sudo.
Как делать не надо
Допустим, мы хотим добавить репозиторий:
sudo echo "deb http://nginx.org/packages/mainline/ubuntu/ jammy nginx" >> /etc/apt/sources.list.d/nginx.listРезультат: bash: /etc/apt/sources.list.d/nginx.list: Permission denied
Почему так происходит?
Дьявол кроется в порядке выполнения команд оболочкой:
- Оболочка сначала обрабатывает оператор
>>. - Именно оболочка (bash/zsh), а не
sudo, пытается открыть файл на запись. Оболочка запущена от вашего текущего пользователя (не root), поэтому прав на запись нет.
Команда
sudoприменяется только кecho, но не к самому процессу записи в файл.
Решение: Команда tee
Используйте утилиту tee. Она читает данные из стандартного ввода и записывает их в файл, при этом выводя их на экран.
Правильный синтаксис:
echo "Hello world" | sudo tee -a /tmp/testfile.txt|(пайп) передает текст команде справа.sudoзапускаетteeс правами суперпользователя.-a(append) - критически важный флаг. Он добавляет текст в конец файла. Без негоteeперезапишет файл целиком!
Мини-демонстрация
Попробуем на безопасном примере:
# Пишем
echo "Hello world" | sudo tee -a /tmp/testfile.txt
# Проверяем
cat /tmp/testfile.txtВывод: Hello world
Продвинутый уровень: Полезные сценарии
Вот как решать более сложные задачи, с которыми echo уже не справляется.
1. Безопасное добавление нескольких строк (Here-Doc)
Если нужно записать целый блок конфига, не нужно делать десять echo. Используйте конструкцию EOF в связке с tee:
cat <<EOF | sudo tee -a /etc/sysctl.conf
# Улучшение сетевых настроек
net.ipv4.tcp_window_scaling = 1
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
EOF
Это чисто, читаемо и выполняется одной транзакцией, не перезаписывает файл.
2. Удаление или замена строк (sed)
Для удаления строк перенаправление не нужно, так как sed умеет редактировать файлы "на месте" (in-place).
Удалить конкретную строку (например, с ошибочным репозиторием):
# Удаляет все строки, содержащие "google-chrome"
sudo sed -i '/google-chrome/d' /etc/apt/sources.listЗаменить одно значение на другое:
# Заменяет "PermitRootLogin yes" на "PermitRootLogin no"
sudo sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_configВажно: Флаг -i изменяет исходный файл. Всегда делайте бэкап перед запуском!
3. Обработка данных и запись в защищённый файл (ss + awk + tee)
Иногда нужно прочитать системный файл, обработать его и записать результат в другой системный файл.
Пример: Сохранить список портов, на которых слушают сервисы.
# awk фильтрует данные, а tee записывает их с правами root
ss -tuln | awk '/LISTEN/ {print $5}' | sudo tee /var/log/active_ports.log > /dev/null
Заметка: > /dev/null в конце нужен, если вы не хотите, чтобы tee дублировал результат вам в консоль.
4. Как делать бэкап "на лету"
При изменении конфигов через sed или tee хорошим тоном считается создание резервной копии.
С sed это очень просто - добавьте расширение после флага -i:
# Создаст файл /etc/hosts.bak перед изменением
sudo sed -i.bak 's/old-ip/new-ip/' /etc/hostsГде это пригодится?
Apt: Добавление репозиториев в
/etc/apt/sources.list.d/Config: Изменение настроек в
/etc/nginx/,/etc/apache2/System: Тюнинг ядра в
/etc/sysctl.confSecurity: Добавление лимитов в
/etc/security/limits.confKeys: Запись бинарных ключей:
cat key.gpg | sudo tee /usr/share/keyrings/app.gpg