Вопрос или проблема
Я хочу добавить больше терминалов в файл /etc/securetty
. Более конкретно, я хотел бы добавить pts/n
, где n
находится в диапазоне 0-9
, если он не существует. Возможно ли это сделать с помощью команды sed
? Ниже приведено содержимое моего /etc/securetty
:
# Локальные X дисплеи (разрешает пустые пароли с помощью nullok_secure от pam_unix)
pts/0
pts/1
pts/2
pts/3
Я попробовал что-то вроде:
sudo sed '+pts/3+a pts/4' /etc/securetty
что вызывает следующую ошибку:
sed: -e выражение #1, символ 3: лишние символы после команды
Мы записываем номер pts/ при встрече соответствующей строки. Опция -p
будет автопечать
строк. Когда мы достигнем eof
, мы извлекаем хэш %h
и передаем его через фильтр grep
, чтобы определить, какие терминалы не были напечатаны, и используем map
, чтобы подготовить формат для этого.
perl -lpe 'm|^pts/([0-9])$| and $h{$1}++;
END{ print for map { "pts/$_" } grep { !$h{$_} } 0 .. 9; }
' /etc/securetty
Мы инициализируем хранящее пространство
с числами 0 1 2 … 9. Каждый раз, когда мы встречаем строку pts/[0-9]
, мы удаляем это из хранящего пространства. На eof
мы получаем доступ к хранящему пространству и, если найдены какие-либо числа, они приводятся к нужному формату и выводятся.
sed -e '
# инициализируем хранящее пространство с 0 1 ... 9
1{x;s|.*|'"$(echo {0..9})"'|;x}
# какой бы ни была строка, её нужно напечатать
p
# мы встречаем действительную строку pts/
\|^pts/[0-9]$|{
# хранящее пространство добавляется к пространству шаблона
G
# захватываем, что это номер pts и ищем его в хранящем
# удаляем его и сохраняем изменения обратно в хранящее пространство.
s|^pts/\([0-9]\)\n\(.*\)\1 |\2|;h
}
# мы еще не достигли eof и обработали вход, так что дальше не идем
$!d
# мы на eof, поэтому возвращаем хранящее пространство. на всякий случай, если все
# номера были обработаны, мы просто заканчиваем. В противном случае, добавляем строку
# pts/ к существующим числам и просто возвращаемся
g;/[0-9]/!d;s/ //g
s|[0-9]|pts/&\n|g;s/.$//
# *ПОДСКАЗКА*: Распределите l, список пространства шаблонов в различных местах, чтобы увидеть,
# что происходит.
' /etc/securetty
Чтобы добавить одну строку, когда её не хватает, это можно сделать, удалив каждое вхождение и добавив его в конец:
sed -n '/pattern/!p;$a pattern'
Но это плохо повторять для 10 шаблонов.
sed '/pts\/[0-9]/d;$a pts/0 ...
это не сработает, если последняя строка должна быть удалена. Таким образом, наоборот, предполагая, что первая строка — единственная, начинающаяся с #
:
sed '/#/a pts/0\
pts/1\
pts/2\
pts/3\
pts/4\
pts/5\
pts/6\
pts/7\
pts/8\
pts\9
/pts\/[0-9]/d'
Плохо. Я предлагаю использовать другой инструмент в этом случае.
Удалите все/любые строки pts/N
, затем добавьте их все обратно:
{ grep -xv '^pts/[0-9]$' /etc/securetty; printf 'pts/%d\n' {0..9}; } > /etc/securetty.new
cat /etc/securetty.new
mv /etc/securetty.new /etc/securetty
Вы также можете сделать это одним махом с вашим любимым инструментом обработки текста, например ed
ed -s /etc/securetty <<IN
g/^pts\/[0-9]$/d
.r ! printf pts/\%d\\\n {0..9}
,p
q
IN
(замените ,p
на w
, чтобы редактировать на месте) или sed
{ printf '%s\\\n' '$a' pts/{0..8}
printf '%s\n' 'pts/9' '/^pts\/[0-9]$/d'
} | sed -f- /etc/securetty
что в принципе то же самое, что и простой
sed '$a\
pts/0\
pts/1\
pts/2\
pts/3\
pts/4\
pts/5\
pts/6\
pts/7\
pts/8\
pts/9
/^pts\/[0-9]$/d' /etc/securetty
(используйте sed
с -i
, чтобы редактировать файл на месте)
Вы можете просмотреть файл securetty и добавить отсутствующие записи следующим образом:
for x in 0 1 2 3 4 5 6 7 8 9
do
grep "pts/${x}" /etc/securetty || echo "pts/${x}" >> /etc/securetty
done
sort /etc/securetty -o /etc/securetty
sed
обрабатывает файл построчно, и его очень сложно заставить “запоминать” какую-либо информацию между строками.
Вы можете использовать grep
, чтобы узнать, содержит ли файл данный шаблон; с помощью -f
вы можете одновременно указать несколько шаблонов. Ниже приведен полный список pts/0
.. pts/9
, затем удаляются шаблоны, уже присутствующие в данном файле, и оставшиеся добавляются в файл:
#!/bin/bash
printf 'pts/%d\n' {0..9} \
| grep -vFf "$1" - >> "$1".new
mv "$1".new "$1"
Вот фрагмент скрипта, который я использую для подготовки машин к ssh-доступу, использующий упомянутый вами шаблон.
Я в основном использую логику из двух этапов:
- 1-й этап: sed используется для удаления строки, содержащей строку.
- 2-й этап: echo tee –append используется для добавления нужного текста в конец файла.
- (Подход не идеален, так как строки меняются, но его легко читать и интуитивно понятно.)
mkdir -p $HOME/.ssh
chmod 700 $HOME/.ssh
echo "ssh-ed25519 AAA...public_ssh_key...ngH arbitrary_comment" | tee -a /home/$USER/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
sudo sed -i "/.*RSAAuthentication.*/d" /etc/ssh/sshd_config
sudo sed -i "/.*PubkeyAuthentication.*/d" /etc/ssh/sshd_config
sudo sed -i "/.*PasswordAuthentication.*/d" /etc/ssh/sshd_config
sudo sed -i "/.*PermitRootLogin.*/d" /etc/ssh/sshd_config
sudo sed -i "/.*PubkeyAcceptedKeyTypes.*/d" /etc/ssh/sshd_config
echo "RSAAuthentication yes" | sudo tee -a /etc/ssh/sshd_config
echo "PubkeyAuthentication yes" | sudo tee -a /etc/ssh/sshd_config
echo "PasswordAuthentication no" | sudo tee -a /etc/ssh/sshd_config
echo "PermitRootLogin no" | sudo tee -a /etc/ssh/sshd_config
echo "PubkeyAcceptedKeyTypes *" | sudo tee -a /etc/ssh/sshd_config
sudo systemctl restart sshd.service
Ответ или решение
Использование команды sed
для проверки существования определенной строки и добавления её в файл, если она отсутствует, может быть довольно непростой задачей, особенно когда речь идет о добавлении строк в файл /etc/securetty
, который контролирует доступ терминалов для пользователей.
Задача
Ваша цель — проверить наличие записей в формате pts/n
, где n
— это число от 0 до 9, и добавить отсутствующие записи в файл /etc/securetty
.
Решение через sed
К сожалению, команда sed
, будучи мощным инструментом для обработки текстов, имеет свои ограничения, особенно в контексте работы с многими строками и условий существования. Однако, мы можем использовать несколько утилит и подходов для достижения желаемого результата. Вот один из вариантов решения с использованием sed
и других команд.
Шаги решения:
-
Удаление существующих записей: Сначала мы удалим все строки, которые соответствуют шаблону
pts/n
, чтобы предотвратить дублирование. -
Добавление недостающих записей: Затем мы добавим записи
pts/0
доpts/9
, которые отсутствуют в файле.
Скрипт для выполнения задачи
Вот пример bash-скрипта, который реализует вышеописанный процесс:
#!/bin/bash
# Удаляем строки, соответствующие pts/[0-9]
sudo sed -i '/^pts\/[0-9]$/d' /etc/securetty
# Добавляем недостающие строки pts/0 до pts/9
for i in {0..9}; do
echo "pts/$i" | sudo tee -a /etc/securetty > /dev/null
done
# Сортируем файл, если это необходимо
sudo sort -o /etc/securetty /etc/securetty
Объяснение кода
-
Удаление строк:
sed -i '/^pts\/[0-9]$/d' /etc/securetty
— эта команда находит и удаляет все строки, которые начинаются сpts/
и заканчиваются на цифру от 0 до 9. Флаг-i
позволяет редактировать файл на месте. -
Добавление недостающих строк: Цикл от
0
до9
генерирует строки и добавляет их в конец файла с помощьюtee
. При этом мы перенаправляем стандартный вывод в/dev/null
, чтобы убрать лишний вывод в терминале. -
Сортировка файла: Мы используем
sort
для упорядочивания записей в файле, хотя это не обязательно, если порядок строк не критичен.
Заключение
Этот подход является эффективным и простым способом проверки наличия строк в файле и их добавления при необходимости. Хотя sed
может быть не самым удобным инструментом для такой задачи, в сочетании с другими командами shell, мы можем добиться необходимого результата. Такой способ минимизирует потенциальные ошибки и облегчает поддержку кода. Обязательно протестируйте скрипт в безопасной обстановке перед применением на производственной системе.