Добавить новую строку только в том случае, если она не существует
Я хочу добавить новую строку в конце файла только в том случае, если она не существует, это значит, что в конце файла несколько строк новой строки.
Я надеюсь использовать sed.
Здесь проблемы, которые возникают у меня с моим текущим кодом:
sed -i -e '/^$/d;$G' /inputfile
echo file1
name1
name2
echo file2
name3
name4
(newline)
когда я запускаю свой код в файлы;
echo file1
name1
name2
(newline)
echo file2
name3
name4
он добавляет новую строку, если она не имеет, но удаляет, если она существует... это меня озадачивает..
Ответы
Ответ 1
Так как он удаляет новую строку, если она не существует, вы можете просто использовать:
echo "" >> file; sed -ie '/^$/d;$G' file; sed -ie '/^$/d;$G' file
Добавляет новую строку и удаляет все, а затем добавляет новую строку. Не изящный способ, но, безусловно, работает:)
Ответ 2
СЕПГ
GNU:
sed -i '$a\' *.txt
OS X:
sed -i '' '$a\' *.txt
$
обращается к последней строке. a\
- это функция добавления.
OS X sed
sed -i '' -n p *.txt
-n
отключает печать, а p
печатает пространство шаблонов. p
добавляет недостающую новую строку в OS X sed, но не в GNU sed, поэтому это не работает с GNU sed.
AWK
awk 1
1
можно заменить на все, что соответствует true. Изменение файла на месте:
{ rm file;awk 1 >file; }<file
bash
[[ $(tail -c1 file) && -f file ]]&&echo ''>>file
Трейлинг новых строк удаляется из результата подстановки команды, поэтому $(tail -c1 file)
пуст, только если file
заканчивается линией перевода или пуст. -f file
является ложным, если file
пусто. [[ $x ]]
эквивалентно [[ -n $x ]]
в bash.
Ответ 3
Вместо того, чтобы обрабатывать весь файл, просто добавьте новую строку в конец, просто проверьте последний символ, и если это не новая строка, добавьте его. Тестирование для новой строки немного интересно, так как оболочка обычно обрезает их с конца строк, поэтому я добавляю "x" для ее защиты:
if [ "$(tail -c1 "$inputfile"; echo x)" != $'\nx' ]; then
echo "" >>"$inputfile"
fi
Обратите внимание, что это добавит новую строку в пустые файлы, которые могут быть не такими, какие вы хотите. Если вы хотите оставить только пустые файлы, добавьте еще один тест:
if [ -s "$inputfile" ] && [ "$(tail -c1 "$inputfile"; echo x)" != $'\nx' ]; then
echo "" >>"$inputfile"
fi
Ответ 4
Использование awk:
awk '/^$/{f=1}END{ if (!f) {print "\r"}}1' inputfile
Сопоставьте пустую строку ^$
(как и вы) и установите флаг. Если флаг не установлен в конце, поместите символ новой строки.
Примечание: \r
находится в OS X. Используйте \n
для других.
Ответ 5
tail -c1 file | read -r _ || echo >> file
получает последний символ файла, который передает его в read
, который выйдет с ненулевым кодом выхода, если он встретит EOF перед новой строкой (так что, если последний символ файла не является новой строкой). Если read
выходит отличным от нуля, добавьте новую строку в файл с помощью echo
(если read
завершает 0, что удовлетворяет ||
, поэтому команда echo
не запускается).
От http://backreference.org/2010/05/23/sanitizing-files-with-no-trailing-newline/.
Ответ 6
Я решил эту задачу, используя dos2unix
(или аналоги) с флагом --newline
. Преимущество заключается в том, что эти инструменты сами определяют двоичные файлы. Мне нравится решение с tail -c1
, но фильтрация двоичных файлов заблаговременно для меня была очень медленной.
dos2unix --newline my_file.txt
В конце концов я написал script, который искал каталог моего проекта, преобразовал все файлы в LF
(dos2unix
), кроме *.cmd
файлов (CRLF
, unix2dos
) и использовал флаг для получения строк новой строки с одним вызовом.
Ответ 7
Попробуйте использовать vi
или ex
:
ex -scwq foo.txt
или для нескольких файлов:
vi -es +"bufdo wq" *.txt
ex -s +"bufdo wq" *.txt
который автоматически добавляет EOL в EOF при сохранении файла, если он отсутствует.
Чтобы рекурсивно применять определенные файлы, используйте новую опцию globbing (**
), например **/*.txt
(enable by shopt -s globstar
).
Ответ 8
Использование только Bash
Вы можете использовать подстановку команд (удалить завершающие символы новой строки) с Here Strings (добавляет новую строку):
Command Substitution
Command substitution allows the output of a command to replace the command name. There are two
forms:
$(command)
or
'command'
Bash performs the expansion by executing command in a subshell environment and replacing the com-
mand substitution with the standard output of the command, with any trailing newlines deleted.
Embedded newlines are not deleted, but they may be removed during word splitting. The command sub-
stitution $(cat file) can be replaced by the equivalent but faster $(< file).
Here Strings
A variant of here documents, the format is:
[n]<<<word
The word undergoes brace expansion, tilde expansion, parameter and variable expansion, command sub-
stitution, arithmetic expansion, and quote removal. Pathname expansion and word splitting are not
performed. The result is supplied as a single string, with a newline appended, to the command on
its standard input (or file descriptor n if n is specified).
Вот как это работает:
cat <<<"$(<inputfile)"
Вывод в файл:
cat <<<"$(<inputfile)" >outputfile
Если вам нужно, чтобы inputfile
и outputfile
inputfile
и то же имя файла, у вас есть пара опций - используйте команду sponge
, сохраните во временную переменную с большей подстановкой команд или сохраните во временный файл.
Используя Sed
Другие предложили использовать
sed '$a\' inputfile
который ничего не добавляет к последней строке. Это нормально, но я думаю
sed '$q' inputfile
немного понятнее, потому что выходит на последней строке. Или вы можете сделать
sed -n 'p'
который использует -n
для подавления вывода, но выводит его обратно с помощью p
.
В любом из этих случаев sed
исправит строку и добавит новую строку, по крайней мере для GNU и BSD sed. Тем не менее, я не уверен, что эта функциональность определяется POSIX. Версия sed
может просто пропустить вашу строку без новой строки, поскольку строка определяется как
Последовательность из нуля или более символов non- плюс завершающий символ.