Используйте команду sed, чтобы проверить, существует ли определенная строка, если нет, добавьте её.

Вопрос или проблема

Я хочу добавить больше терминалов в файл /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 и других команд.

Шаги решения:

  1. Удаление существующих записей: Сначала мы удалим все строки, которые соответствуют шаблону pts/n, чтобы предотвратить дублирование.

  2. Добавление недостающих записей: Затем мы добавим записи 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

Объяснение кода

  1. Удаление строк: sed -i '/^pts\/[0-9]$/d' /etc/securetty — эта команда находит и удаляет все строки, которые начинаются с pts/ и заканчиваются на цифру от 0 до 9. Флаг -i позволяет редактировать файл на месте.

  2. Добавление недостающих строк: Цикл от 0 до 9 генерирует строки и добавляет их в конец файла с помощью tee. При этом мы перенаправляем стандартный вывод в /dev/null, чтобы убрать лишний вывод в терминале.

  3. Сортировка файла: Мы используем sort для упорядочивания записей в файле, хотя это не обязательно, если порядок строк не критичен.

Заключение

Этот подход является эффективным и простым способом проверки наличия строк в файле и их добавления при необходимости. Хотя sed может быть не самым удобным инструментом для такой задачи, в сочетании с другими командами shell, мы можем добиться необходимого результата. Такой способ минимизирует потенциальные ошибки и облегчает поддержку кода. Обязательно протестируйте скрипт в безопасной обстановке перед применением на производственной системе.

Оцените материал
Добавить комментарий

Капча загружается...