Удалите любые строки конечного пробела или строки с пробелами от конца файла

Я хочу добраться, удаляют все пустые строки и строки с пробелами (если кто-либо существует (ТОЛЬКО от нижней части файла)) и затем удалить еще одну строку (также ТОЛЬКО от нижней части файла).

У меня есть этот код:

while [[ "$last_line" =~ $ ]] || [[ "$last_line" =~ ^[[:space:]]+$ ]]
do
    sed -i -e '${/$/d}' "./file.txt"
done
    sed -i -e '${/$/d}' "./file.txt"

По некоторым причинам цикл не останавливается, и он удаляет все в файле.В чем дело?

3
задан 12 August 2015 в 07:58

4 ответа

Ваш сценарий должен работать, если зафиксировано как так:

while
 last_line=$(tail -1 "./file.txt")
 [[ "$last_line" =~ ^$ ]] || [[ "$last_line" =~ ^[[:space:]]+$ ]]
do
 sed -i '$d' "./file.txt"
done

Ваш сценарий имел две основных проблемы: (1) Вы никогда не обновляли $last_line, таким образом, защита цикла будет всегда оценивать то же самое; (2) Ваш [[ "$last_line" =~ $ ]] тест соответствовал любой строка, так как любая строка имеет конец. (Это - причина, почему Ваш сценарий освободил Ваш файл полностью.) Вы, вероятно, хотите соответствовать против ^$ вместо этого, который соответствует только пустым строкам. Кроме того, я упростил эти sed команда для удаления последней строки в теле цикла (просто $d, делает задание).

Однако этот сценарий является излишне сложным. sed там для просто такой вещи! Эта острота сделает то же самое как вышеупомянутый сценарий:

sed -i ':a;/^[ \n]*$/{$d;N;ba}' ./file.txt

Примерно,

  1. Соответствие текущая строка против ^[ \n]*$. (т.е., может только содержать пробелы и новые строки)
  2. , Если это не соответствует, просто печатает его. Читайте в следующей строке и продолжите шаг 1.
  3. , Если это действительно соответствует,
    • , Если мы в конце файла, удаляем его.
    • , Если мы не в конце файла, , добавляют следующая строка к текущей строке, вставляя символ новой строки между этими двумя, и возвращаются к шагу 1 с этой новой, более длинной строкой.

существует много потрясающих sed учебные руководства в Интернете. Например, я могу рекомендовать этот . Счастливое изучение! :-)

Обновление: И конечно, если Вы дополнительно хотите удалить последнюю (непустую) строку файла после наличия усеченного строки конечного пробела, можно просто использовать другой sed -i '$d' ./file.txt или после сценария или после вышеупомянутой остроты. Я намеренно не хотел включать это в sed острота, так как я думал, что удаление строк конечного пробела является вполне допускающей повторное использование частью кода, который может быть интересным для других людей; но удаление последней непустой строки действительно характерно для Вашего варианта использования и тривиально так или иначе, после того как Вы удалили строки конечного пробела.

4
ответ дан 1 December 2019 в 13:16

Как я понимаю

  • , Удаляют пустые строки из конца файла
  • , Удаляют строки с пробелами от конца файла
  • И затем , удаляют еще одну строку

Используя awk и tac

tac foo | awk '! non_empty && ! /^$/ && ! /[ \t]/ {non_empty = 1} non_empty {skip++} skip > 1 {print}' | tac
[еще 1112] изменения ниже примера †¦

<час>

Пример

% cat -n foo                                                                
     1  line1
     2  line2
     3  line3
     4  
     5  
     6  line6
     7  line 7 
     8  

% tac foo | awk '! non_empty && ! /^$/ && ! /[ \t]/ {non_empty = 1} non_empty {skip++} skip > 1 {print}' | tac > bar

% cat -n bar
     1  line1
     2  line2
     3  line3
     4  
     5  
<час>

Для удаления только пустых строк в конце файла

tac foo | awk '! non_empty && ! /^$  {non_empty = 1} non_empty {print}' | tac
<час>

Для удаления пустых строк в конце и еще одной строке

tac foo | awk '! non_empty && ! /^$/ &&  {non_empty = 1} non_empty {skip++} skip > 1 {print}' | tac
0
ответ дан 1 December 2019 в 13:16

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

tac infile | awk 'flag {print} {if(NF) flag=1}' | tac | sponge infile

Как указано в комментариях Malte Skoruppa и zwets, Ubuntu не идет moreutils пакет предварительно установил, который содержит sponge; альтернативное решение состоит в том, чтобы использовать замену команды в herestring для чтения входного файла, так, чтобы, будучи заменой команды, обработанной сначала, файл был безопасен быть усеченным вторым tac команда:

<<<"$(< infile)" tac | awk 'flag {print} {if(NF) flag=1}' | tac > infile
  • tac infile:... делает противоположность cat infile (!): печатает файл к stdout инвертирование порядка строки;
  • awk [...]: обрабатывает файл;
  • tac:... делает противоположность cat (!): печатает файл к stdout инвертирование порядка строки;
  • sponge infile: выводы к infile только, когда левая сторона канала завершила свое выполнение, чтобы не усекать infile прежде чем это будет считано первым tac команда;

awk разбивка команды:

  • flag {print}: если flag установлен, это распечатает строку; flag не будет установлен до записи чей NF оцените соответствует числу, больше, чем 0 обрабатывается, поэтому до записи чей NF оцените соответствует числу, больше, чем 0 не найден, print команда будет пропущена;
  • {if(NF) flag=1}: если, в то время как flag все еще сброшен запись чей NF оцените соответствует числу, больше, чем 0 обрабатывается, это не будет распечатано и flag будет установлен на 1, так первая запись, чей NF оцените соответствует числу, больше, чем 0 не будет распечатан;

Тест на тестовом файле (ум, что строка 4 и строка 7 содержат 5 пробелов, в то время как строка 5 и строка 8 пусты):

user@debian ~ % cat infile                                           
line1
line2
line3


line6


user@debian ~ % tac infile | awk 'flag {print} {if(NF) flag=1}' | tac
line1
line2
line3


user@debian ~ % 

Строка 7 и строка 8 были удалены, потому что они были оба в конце файла, содержание только располагает с интервалами (строка 7) или содержащий ничто (строка 8); строка 6 была удалена, потому что это было первое, читая строки файла в противоположном порядке, чтобы иметь по крайней мере 1 поле (следовательно не являющийся пустым или содержащий только располагает с интервалами),

4
ответ дан 1 December 2019 в 13:16

Править

Так первоначально я упустил суть, что OP хочет удалить только последнюю пустую строку, которую мое исходное решение делает также. Тем не менее, вот версия, которая удаляет только последний, и если его пробел.

awk -v numlines=$(wc -l file2|cut -f1 -d' ') 'NR < numlines; END {if (NF) print }' file2

То, что делает код, довольно просто - получают количество строк и печатают каждую строку, до последней. На последнем мы проверяем, содержит ли строка какие-либо поля; если существует какой-либо текст, NF оценивает к целому числу (верному) таким образом печатающая последняя строка, и если нет ничего или не располагает с интервалами только - NF оценивает для обнуления (ложь) и не печатает ничто больше.

Что касается удаления еще одной строки, head -n -1 сделаю.

Рев является маленькой демонстрацией. Запаздывающая новая строка определяется с $ подсказка *$

*$ cat -A file2                                                                                                                                      
212$
1231$
$
324234$
213$
$
*$ awk -v numlines=$(wc -l file2|cut -f1 -d' ')  'NR < numlines ; END {if ( NF ) print }' file2 | head -n -1                                         
212
1231

324234

Исходный

awk решение.

awk 'NF' file1 > /tmp/tmpfile && cat /tmp/tmpfile > file1

Здесь мы используем Количество Полевой переменной как тест для печати. Для пустых строк количество полей является нулем, следовательно это, оценка пустых строк ко лжи не будет распечатана. Теперь, если Ваш awk встроенное редактирование поддержки версии (который является gnu awk or gawk, Я думаю), необходимо перенаправить вывод к временному выводу и назад в исходный файл с cat, как я сделал здесь

Вариация на тему должна была бы использовать regex, чтобы протестировать, если строки содержат некоторые конкретные данные, как цифры или алфавитно-цифровые символы, например.

awk '$0~/[[:digit:]]||[[:alpha:]]/ ' file1 > /tmp/tmpfile && cat /tmp/tmpfile > file1

0
ответ дан 1 December 2019 в 13:16

Другие вопросы по тегам:

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