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

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

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

Ответы [ 13 ]

49 голосов
/ 09 сентября 2011

С Полезные однострочные скрипты для sed :

# Delete all leading blank lines at top of file (only).
sed '/./,$!d' file

# Delete all trailing blank lines at end of file (only).
sed -e :a -e '/^\n*$/{$d;N;};/\n$/ba' file

Поэтому, чтобы удалить как начальные, так и конечные пустые строки из файла, вы можете объединить приведенные выше команды в:

sed -e :a -e '/./,$!d;/^\n*$/{$d;N;};/\n$/ba' file
10 голосов
/ 27 мая 2014

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

tac является частьюиз coreutils и переворачивает файл.Так что сделайте это дважды:

tac file | sed -e '/./,$!d' | tac | sed -e '/./,$!d'

Это, конечно, не самый эффективный, но если вам не нужна эффективность, я считаю его более читабельным, чем все остальное до сих пор.

3 голосов
/ 09 сентября 2011

вот однопроходное решение в awk: оно не начинает печатать, пока не увидит непустую строку, а когда увидит пустую строку, запоминает его до следующей непустой строки

awk '
    /[[:graph:]]/ {
        # a non-empty line
        # set the flag to begin printing lines
        p=1      
        # print the accumulated "interior" empty lines 
        for (i=1; i<=n; i++) print ""
        n=0
        # then print this line
        print
    }
    p && /^[[:space:]]*$/ {
        # a potentially "interior" empty line. remember it.
        n++
    }
' filename

Обратите внимание, что из-за механизма, который я использую для рассмотрения пустых / непустых строк (с [[:graph:]] и /^[[:space:]]*$/), внутренние линии с одним пробелом будут обрезаны, чтобы стать по-настоящему пустыми.

2 голосов
/ 05 марта 2015

Вот адаптированная версия sed, которая также считает «пустыми» эти строки, содержащие только пробелы и символы табуляции.

sed -e :a -e '/[^[:blank:]]/,$!d; /^[[:space:]]*$/{ $d; N; ba' -e '}'

Это в основном принятая версия ответа (с учетом комментария BryanH), но точка . в первой команде была изменена на [^[:blank:]] (что-то не пустое), а \n внутри адреса второй команды была изменена на [[:space:]], чтобы разрешить переводы строк, пробелы и символы табуляции.

Альтернативная версия, без использования классов POSIX, но ваш sed должен поддерживать вставку \t и \n внутри […]. GNU sed делает, BSD sed не делает.

sed -e :a -e '/[^\t ]/,$!d; /^[\n\t ]*$/{ $d; N; ba' -e '}'

Тестирование:

prompt$ printf '\n \t \n\nfoo\n\nfoo\n\n \t \n\n' 



foo

foo



prompt$ printf '\n \t \n\nfoo\n\nfoo\n\n \t \n\n' | sed -n l
$
 \t $
$
foo$
$
foo$
$
 \t $
$
prompt$ printf '\n \t \n\nfoo\n\nfoo\n\n \t \n\n' | sed -e :a -e '/[^[:blank:]]/,$!d; /^[[:space:]]*$/{ $d; N; ba' -e '}'
foo

foo
prompt$
2 голосов
/ 07 июля 2014

Как уже упоминалось в , другой ответ , tac является частью coreutils и переворачивает файл.Комбинируя идею сделать это дважды с тем фактом, что подстановка команд уберет завершающие новые строки , мы получим

echo "$(echo "$(tac "$filename")" | tac)"

, который не зависит от sed.Вы можете использовать echo -n для удаления оставшегося завершающего символа новой строки.

2 голосов
/ 09 сентября 2011

с использованием awk:

awk '{a[NR]=$0;if($0 && !s)s=NR;}
    END{e=NR;
        for(i=NR;i>1;i--) 
            if(a[i]){ e=i; break; } 
        for(i=s;i<=e;i++)
            print a[i];}' yourFile
1 голос
/ 30 июня 2017

Для эффективной нерекурсивной версии конечной полосы перевода строки (включая «белые» символы) я разработал этот скрипт sed.

sed -n '/^[[:space:]]*$/ !{x;/\n/{s/^\n//;p;s/.*//;};x;p;}; /^[[:space:]]*$/H'

Он использует буфер удержания для хранения всех пустых строк и печатает их только после того, как обнаружит непустую строку. Если кому-то нужны только новые строки, достаточно избавиться от двух [[:space:]]* частей:

sed -n '/^$/ !{x;/\n/{s/^\n//;p;s/.*//;};x;p;}; /^$/H'

Я попробовал простое сравнение производительности с известным рекурсивным скриптом

sed -e :a -e '/^\n*$/{$d;N;};/\n$/ba'

в 3 МБ файле с 1 МБ случайных пустых строк вокруг случайного текста base64.

shuf -re 1 2 3 | tr -d "\n" | tr 123 " \t\n" | dd bs=1 count=1M > bigfile
base64 </dev/urandom | dd bs=1 count=1M >> bigfile
shuf -re 1 2 3 | tr -d "\n" | tr 123 " \t\n" | dd bs=1 count=1M >> bigfile

Потоковый скрипт завершился примерно за 0,5 секунды, рекурсия не завершилась через 15 минут. Win:)

Для полноты ответа ответ на сценарий sed с ведущими строками уже работает нормально. Используйте наиболее подходящий для вас.

sed '/[^[:blank:]]/,$!d'
sed '/./,$!d'
1 голос
/ 09 сентября 2011

Использование bash

$ filecontent=$(<file)
$ echo "${filecontent/$'\n'}"
1 голос
/ 09 сентября 2011

В bash, используя cat, wc, grep, sed, tail и head:

# number of first line that contains non-empty character
i=`grep -n "^[^\B*]" <your_file> | sed -e 's/:.*//' | head -1`
# number of hte last one
j=`grep -n "^[^\B*]" <your_file> | sed -e 's/:.*//' | tail -1`
# overall number of lines:
k=`cat <your_file> | wc -l`
# how much empty lines at the end of file we have?
m=$(($k-$j))
# let strip last m lines!
cat <your_file> | head -n-$m
# now we have to strip first i lines and we are done 8-)
cat <your_file> | tail -n+$i

Чувак, определенно стоит выучить "настоящий" язык программирования, чтобы избежать этого безобразия!

0 голосов
/ 03 ноября 2018

Этот скрипт AWK поможет:

BEGIN {
    ne=0;
}

/^[[:space:]]*$/ {
    ne++;
}

/[^[:space:]]+/ {
    for(i=0; i < ne; i++)
        print "";
    ne=0;
    print
}

Идея проста: пустые строки не сразу отражаются.Вместо этого мы ждем, пока не получим непустую строку, и только затем мы сначала выводим столько пустых строк, сколько было видно перед ней, и только затем выводим новую непустую строку.

...