Удаление завершающих / запускающих строк с помощью sed, awk, tr и friends - PullRequest
36 голосов
/ 09 сентября 2011

Я хотел бы удалить все пустые строки из файла, но только когда они находятся в конце / начале файла (то есть, если перед ними нет непустых строк, в начале; и если после них нет непустых строк, в конце.)

Возможно ли это за пределами полнофункционального языка сценариев, такого как Perl или Ruby? Я бы предпочел сделать это с sed или awk, если это возможно. В принципе, подойдет любой легкий и широко доступный инструмент UNIX-y, особенно тот, о котором я могу узнать быстрее (Perl, таким образом, не включен).

Ответы [ 13 ]

0 голосов
/ 30 января 2015

@ dogbane имеет хороший простой ответ для удаления начальных пустых строк.Вот простая команда awk, которая удаляет только завершающие строки.Используйте это вместе с командой sed @ dogbane для удаления начальных и конечных пробелов.

awk '{ LINES=LINES $0 "\n"; } /./ { printf "%s", LINES; LINES=""; }'

Это довольно просто в работе.

  • Добавлять каждую строку в буфер по мере его чтения.
  • Для каждой строки, которая содержит символ, распечатайте содержимое буфера и затем очистите его.

Таким образом, единственные вещи, которые буферизуются и никогда не отображаются, это любые пробелы в конце.

Я использовал printf вместо print, чтобы избежать автоматического добавления новой строки, поскольку я использую новые строки для разделения строк в буфере.

0 голосов
/ 02 ноября 2014

Я хотел бы представить другой вариант для gawk v4.1 +

result=($(gawk '
    BEGIN {
        lines_count         = 0;
        empty_lines_in_head = 0;
        empty_lines_in_tail = 0;
    }
    /[^[:space:]]/ {
        found_not_empty_line = 1;
        empty_lines_in_tail  = 0;
    }
    /^[[:space:]]*?$/ {
        if ( found_not_empty_line ) {
            empty_lines_in_tail ++;
        } else {
            empty_lines_in_head ++;
        }
    }
    {
        lines_count ++;
    }
    END {
        print (empty_lines_in_head " " empty_lines_in_tail " " lines_count);
    }
' "$file"))

empty_lines_in_head=${result[0]}
empty_lines_in_tail=${result[1]}
lines_count=${result[2]}

if [ $empty_lines_in_head -gt 0 ] || [ $empty_lines_in_tail -gt 0 ]; then
    echo "Removing whitespace from \"$file\""
    eval "gawk -i inplace '
        {
            if ( NR > $empty_lines_in_head && NR <= $(($lines_count - $empty_lines_in_tail)) ) {
                print
            }
        }
    ' \"$file\""
fi
0 голосов
/ 07 июля 2014

A bash раствор .

Примечание: полезно , только если файл достаточно мал для немедленного считывания в память.

[[ $(<file) =~ ^$'\n'*(.*)$ ]] && echo "${BASH_REMATCH[1]}"
  • $(<file) читает весь файл и обрезает завершающие новые строки, потому что подстановка команд ($(....)) неявно делает это.
  • =~ является оператором сопоставления регулярных выражений bash , а =~ ^$'\n'*(.*)$ опционально сопоставляет любые начальные новые строки (жадно) и захватывает все, что будет после. Обратите внимание на потенциально запутанный $'\n', который вставляет буквальный перевод строки, используя ANSI C, цитируя , потому что escape-последовательность \n не поддерживается.
  • Обратите внимание, что это конкретное регулярное выражение всегда соответствует, поэтому команда после && является всегда выполненной.
  • Специальная переменная массива BASH_REMATCH rematch содержит результаты последнего совпадения с регулярным выражением, а элемент массива [1] содержит то, что перехвачено (первое и единственное) заключенное в скобки подвыражение (группа захвата), которое является входной строкой с любым ведущим новые строки разорваны. Чистый эффект состоит в том, что ${BASH_REMATCH[1]} содержит содержимое входного файла с разделенными начальными и конечными символами новой строки.
  • Обратите внимание, что печать с echo добавляет один завершающий перевод строки. Если вы хотите избежать этого, используйте echo -n вместо этого (или используйте более переносимый printf '%s').
...