Чего вам не хватает, так это того, что большинство описаний терминалов ( linux
здесь в меньшинстве из-за повсеместного использования жестко запрограммированных строк в .inputrc
) используют прикладной режим для специальных ключей. Это отличает клавиши управления курсором, показанные в tput
и infocmp
, от того, что отправляет ваш (неинициализированный) терминал. Приложения curses всегда инициализируют терминал, а база данных терминала используется для этой цели.
dialog
имеет свое применение, но не решает напрямую этот вопрос. С другой стороны, это громоздко (технически выполнимо , редко сделано ) предоставлять решение только для bash. Обычно для этого мы используем другие языки.
Проблема с чтением специальных ключей заключается в том, что они часто состоят из нескольких байтов, включая неудобные символы, такие как escape и ~ . Вы можете сделать это с помощью bash, но тогда вы должны решить проблему переносимого определения, какой это был специальный ключ.
диалоговое окно
одновременно обрабатывает ввод специальных клавиш и берет на себя (временно) ваш дисплей. Если вам действительно нужна простая программа из командной строки, это не диалог
.
Вот простая программа на C, которая считывает специальный ключ и печатает его в печатной (и переносимой) форме:
#include
int
main(void)
{
int ch;
const char *result;
char buffer[80];
filter();
newterm(NULL, stderr, stdin);
keypad(stdscr, TRUE);
noecho();
cbreak();
ch = getch();
if ((result = keyname(ch)) == 0) {
/* ncurses does the whole thing, other implementations need this */
if ((result = unctrl((chtype)ch)) == 0) {
sprintf(buffer, "%#x", ch);
result = buffer;
}
}
endwin();
printf("%s\n", result);
return 0;
}
Предположим, что это было вызвано tgetch
, вы бы использовали это в вашем скрипте, например:
case $(tgetch 2>/dev/null) in
KEY_UP)
echo "got cursor-up"
;;
KEY_BACKSPACE|"^H")
echo "got backspace"
;;
esac
Дополнительная литература:
\.
и [.]
эквивалентны — они оба соответствуют буквальной точке, а не любой другой персонаж. Что касается стиля, выберите один из них и последовательно используйте его. ([^.]+\.)+
, за которым следует [.]+
. Это действительно (вроде )эквивалентно [^.]+\.
, за которым следует [.]
, в результате ваш grep ищет строки, содержащие text.text..
, то есть две точки подряд. Если вы проверите, то увидите, что ваша команда соответствует a.b..
. grep -P '^[^.]+\.([^.]+\.)+[^.]*$'Т.е. изменить
[.]
на [^.]
(, возможно, это то, что вы имели в виду изначально? ), измените следующее +
на *
и добавьте $
. После некоторого количества text.
групп требовать/разрешать любое число (ноль или более )символов, отличных от точки, до конца строки. grep -P '^[^.]+\..*\.' file.txt | grep -v '\.\.'Первый
grep
находит строки, начинающиеся с символа точки, отличного от -. и включите по крайней мере две точки. Второй grep
удаляет строки с двумя последовательными точками. grep … | wc -l
просто выполните grep -c …
.Использованиеawk
:
$ cat file
.com
.c.c.c.c
a.b.
a.b.com
a.b.c.
a.b.c.com
a.com
a..b
a.b.c..d
$ awk -F. 'NF > 2 && !/^\./ && !/\.\./' file
a.b.
a.b.com
a.b.c.
a.b.c.com
Программа awk
использует точку в качестве разделителя полей. Строка с двумя или более точками аналогична строке с более чем двумя полями. Это то, что проверяет тест NF > 2
. Первое регулярное выражение отбрасывает строки, начинающиеся с точки, а второе регулярное выражение отбрасывает строки, содержащие две точки или более подряд. Остальные строки печатаются.
То же самое сgrep
:
grep '\..*\.' file | grep -v -e '^\.' -e '\.\.'
Первое выражение извлекает строки, содержащие как минимум две точки, а два других удаляют строки, начинающиеся с точки или содержащие две последовательные точки.
Или с sed
,
sed -n '/^\./d; /\.\./d; /\..*\./p' file
Это можно сделать с помощью обхода, как показано на рисунке:
$ grep -Pc '^(?!\.)(?!.*\.\..*)(?=.*\..*\.)' file.txt
Читать как:
^
(?!\.)
(?!.*\.\..*)
(?=.*\..*\.)