Я хочу добавить больше терминалов в файл /etc/securetty
. А точнее, я хотел бы добавить pts/n
, где n
находится в диапазоне 0-9
, если он не существует. Возможно ли это через sed
команду? Ниже показано, как /etc/securetty
выглядит содержимое моего:
# Local X displays (allows empty passwords with pam_unix's nullok_secure)
pts/0
pts/1
pts/2
pts/3
Я попробовал что-то вроде:
sudo sed '+pts/3+a pts/4' /etc/securetty
что приводит к следующей ошибке:
sed: -e expression #1, char 3: extra characters after command
решение1
Мы записываем номер pts/, когда встречаем соответствующую строку. Опция -p
будет autoprint
строк. Когда мы достигаем, eof
мы вытаскиваем хэш %h
и передаем его через grep
фильтр, чтобы определить, какие терминалы не печатали, и мы используем map
для подготовки формата для этого.
perl -lpe 'm|^pts/([0-9])$| and $h{$1}++;
END{ print for map { "pts/$_" } grep { !$h{$_} } 0 .. 9; }
' /etc/securetty
Мы инициализируем hold space
числами 0 1 2 ... 9. Всякий раз, когда мы встречаем строку pts/[0-9]
, мы вырезаем ее из удерживаемого пространства. В eof
мы получаем удерживаемое пространство и, если какие-либо числа найдены, преобразуем в правильный формат и распечатываем.
sed -e '
# initialize the hold space with 0 1 ... 9
1{x;s|.*|'"$(echo {0..9})"'|;x}
# whatever be the line, it needs to be printed
p
# we meet a valid pts/ line
\|^pts/[0-9]$|{
# the hold space gets appended to the pattern space
G
# grab what is the pts number and search for it in the hold and
# delete itand store back the changes into hold space.
s|^pts/\([0-9]\)\n\(.*\)\1 |\2|;h
}
# weve not arrived at the eof and weve processed the input so go no further
$!d
# we are at the eof, so we bring back the hold space. just in case all
# numbers were dealt with up, we simply bail out. Else, prepend the str
# pts/ to the numbers present and simply were home
g;/[0-9]/!d;s/ //g
s|[0-9]|pts/&\n|g;s/.$//
# *TIP*: Sprinkle the l, list pattern space at various places to see
# whats going on.
' /etc/securetty
решение2
Чтобы добавить одну строку, если она отсутствует, можно удалить каждое вхождение и добавить его в конец:
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'
Гадость. Предлагаю в этом случае использовать другой инструмент.
решение3
Удалите любые/все 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
для редактирования файла на месте)
решение4
sed
обрабатывает файл строка за строкой, и очень сложно заставить его «запомнить» какую-либо информацию между строк.
Вы можете использовать grep
для определения, содержит ли файл заданный шаблон; с помощью -f
вы можете предоставить несколько шаблонов одновременно. Следующий код генерирует полный список pts/0
.. pts/9
, затем удаляет шаблоны, уже присутствующие в заданном файле, и добавляет оставшиеся в файл:
#!/bin/bash
printf 'pts/%d\n' {0..9} \
| grep -vFf "$1" - >> "$1".new
mv "$1".new "$1"