Скажем, у меня есть несколько произвольных многострочных текстовых файлов:
sometext
moretext
lastline
Как удалить только последний символ (e, а не новую строку или нуль) файла, не делая текстовый файл недействительным?
Скажем, у меня есть несколько произвольных многострочных текстовых файлов:
sometext
moretext
lastline
Как удалить только последний символ (e, а не новую строку или нуль) файла, не делая текстовый файл недействительным?
Более простой подход (выходы на stdout, не обновляет входной файл):
sed '$ s/.$//' somefile
$
- это Sed-адрес, который соответствует только последней строке ввода, что вызывает выполнение следующего вызова функции (s/.$//
) только в последней строке.s/.$//
заменяет последний символ строки (в данном случае последней) пустой строкой; то есть эффективно удаляет последний char. (перед новой строкой) на линии. .
соответствует любому символу в строке, а после него с $
привязывает соответствие к концу строки; обратите внимание, как использование $
в этом регулярном выражении концептуально связано, но технически отличается от предыдущего использования $
в качестве Sed-адреса.Пример со входом stdin (предполагается Bash, Ksh или Zsh):
$ sed '$ s/.$//' <<< $'line one\nline two'
line one
line tw
Также обновить файл ввода (не использовать, если входной файл является символической ссылкой):
sed -i '$ s/.$//' somefile
Примечание:
* В OSX вам нужно будет использовать -i ''
вместо -i
; для обзора подводных камней, связанных с -i
, см. нижнюю часть моего ответа здесь.
* Если вам нужно обрабатывать очень большие входные файлы и/или производительность/использование диска, вы беспокоитесь, и вы используете утилиты GNU (Linux), см. отзыв о сотернаре.
truncate
truncate -s-1 file
Удаляет один (-1) символ из конца того же файла. Точно, как >>
будет добавляться в тот же файл.
Проблема с этим подходом заключается в том, что он не сохраняет конечную новую строку, если она существует.
Решение:
if [ -n "$(tail -c1 file)" ] # if the file has not a trailing new line.
then
truncate -s-1 file # remove one char as the question request.
else
truncate -s-2 file # remove the last two characters
echo "" >> file # add the trailing new line back
fi
Это работает, потому что tail принимает последний байт (не char).
Для больших файлов требуется почти время.
Почему бы не sed
Проблема с решением sed, например sed '$ s/.$//' file
, заключается в том, что он сначала считывает весь файл (длительное время с большими файлами), тогда вам нужен временный файл (того же размера, что и оригинал):
sed '$ s/.$//' file > tempfile
rm file; mv tempfile file
И затем переместите файл temp, чтобы заменить файл.
Здесь другой, использующий ex
, который я считаю не таким загадочным, как решение sed:
printf '%s\n' '$' 's/.$//' wq | ex somefile
$
переходит к последней строке, s
удаляет последний символ, а wq
- хорошо известный (для пользователей vi) write + quit.
После целой группы игр с разными стратегиями (и избегая sed -i или perl), лучший способ, которым я нашел это, заключался в следующем:
sed '$! { P; D; }; s/.$//' somefile
ОТДЕЛЬНЫЙ ОТВЕТ
Я создал script и разместил текст на своем рабочем столе. этот тестовый файл сохраняется как "old_file.txt"
sometext
moretext
lastline
Затем я написал небольшой script, чтобы взять старый файл и исключить символ last в последней строке
#!/bin/bash
no_of_new_line_characters=`wc '/root/Desktop/old_file.txt'|cut -d ' ' -f2`
let "no_of_lines=no_of_new_line_characters+1"
sed -n 1,"$no_of_new_line_characters"p '/root/Desktop/old_file.txt' > '/root/Desktop/my_new_file'
sed -n "$no_of_lines","$no_of_lines"p '/root/Desktop/old_file.txt'|sed 's/.$//g' >> '/root/Desktop/my_new_file'
открытие нового файла, который я создал, показал результат следующим образом:
sometext
moretext
lastlin
Приносим извинения за мой предыдущий ответ (не читал внимательно)
Если цель состоит в том, чтобы удалить последний символ в последней строке, этот awk
должен сделать:
awk '{a[NR]=$0} END {for (i=1;i<NR;i++) print a[i];sub(/.$/,"",a[NR]);print a[NR]}' file
sometext
moretext
lastlin
Сохраняет все данные в массиве, затем распечатывает и изменяет последнюю строку.
Просто замечание: sed временно удалит файл. Поэтому, если вы завершаете файл, вы получите предупреждение "Нет такого файла или каталога", пока вы не переиздаете команду "хвост".
sed 's/.$//' filename | tee newFilename
Это должно выполнить вашу работу.