Извлечь строки, содержащие две или более точек

Чего вам не хватает, так это того, что большинство описаний терминалов ( 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

Дополнительная литература:

3
22.04.2019, 02:31
3 ответа
  1. \.и [.]эквивалентны — они оба соответствуют буквальной точке, а не любой другой персонаж. Что касается стиля, выберите один из них и последовательно используйте его.
  2. Ваша проблема в том, что ваше регулярное выражение (, т. е. шаблон )имеет ([^.]+\.)+, за которым следует [.]+. Это действительно (вроде )эквивалентно [^.]+\., за которым следует [.], в результате ваш grep ищет строки, содержащие text.text.., то есть две точки подряд. Если вы проверите, то увидите, что ваша команда соответствует a.b...
  3. Хорошо, я думаю, что исправление довольно простое :
    grep -P '^[^.]+\.([^.]+\.)+[^.]*$'
    Т.е. изменить [.]на [^.](, возможно, это то, что вы имели в виду изначально? ), измените следующее +на *и добавьте $. После некоторого количества text.групп требовать/разрешать любое число (ноль или более )символов, отличных от точки, до конца строки.
  4. Еще более простым подходом (, более понятным ), был бы
    grep -P '^[^.]+\..*\.' file.txt | grep -v '\.\.'
    Первый grepнаходит строки, начинающиеся с символа точки, отличного от -. и включите по крайней мере две точки. Второй grepудаляет строки с двумя последовательными точками.
  5. Вместо grep … | wc -lпросто выполните grep -c ….
4
27.01.2020, 21:17

Использование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
1
27.01.2020, 21:17

Это можно сделать с помощью обхода, как показано на рисунке:

$ grep -Pc '^(?!\.)(?!.*\.\..*)(?=.*\..*\.)' file.txt

Читать как:

  • Я стою в начале очереди и смотрю направо^
  • Я вижу, что строка не начинается с буквальной точки(?!\.)
  • Глядя дальше вперед, я нигде не вижу двух последовательных буквальных точек(?!.*\.\..*)
  • Но я вижу две точки, но поскольку последовательные точки были исключены в моем предыдущем просмотре вперед, это означает, что эти две точки ДОЛЖНЫ быть разделены по крайней мере одним не -точечным символом(?=.*\..*\.)
  • К.Э.Д.
0
27.01.2020, 21:17

Теги

Похожие вопросы