linux 仅在换行符不存在时添加换行符

w41d8nur  于 2022-11-22  发布在  Linux
关注(0)|答案(9)|浏览(197)

我只想在文件末尾添加一个不存在的换行符。这是为了防止在文件末尾出现多个换行符。
我希望使用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

如果没有换行符,它会添加一个换行符;如果存在换行符,它会删除换行符......这让我很困惑。

yhuiod9q

yhuiod9q1#

已删除

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(数字1)可以替换为计算结果为true的任何值。就地修改文件:

{ rm file;awk 1 >file; }<file

狂欢

[[ $(tail -c1 file) && -f file ]]&&echo ''>>file

将从命令替换的结果中删除尾随换行符,因此只有当file以换行符结尾或为空时,$(tail -c1 file)才为空。如果file为空,则-f file为false。[[ $x ]]等效于bash中的[[ -n $x ]]

lztngnrs

lztngnrs2#

不是用see处理整个文件,只是在结尾处添加一个换行符,而是检查最后一个字符,如果它 * 不是 * 换行符,就追加一个。测试换行符有点意思,因为shell通常会从字符串结尾处删除它们,所以我追加“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
0yg35tkg

0yg35tkg3#

由于它会删除不存在的换行符,因此您可以简单地用途:

echo "" >> file;  sed -ie '/^$/d;$G' file; sed -ie '/^$/d;$G' file

添加一个新行并删除所有内容,然后添加新行。不是优雅的方式,但肯定有效:)

zrfyljdw

zrfyljdw4#

tail -c1 file | read -r _ || echo >> file

获取文件的最后一个字符,将其管道化到read中,如果在换行符前遇到EOF,则read将以非零退出代码退出如果read以非零值存在,则使用echo在文件上追加一个换行符(如果read退出0,说明满足||,所以echo命令不运行)。
http://backreference.org/2010/05/23/sanitizing-files-with-no-trailing-newline/开始。

csga3l58

csga3l585#

使用awk:

awk '/^$/{f=1}END{ if (!f) {print "\r"}}1' inputfile

匹配空行^$(就像你做的那样)并设置一个标志。如果末尾没有设置标志,则放置换行符。
注:\r在OS X中。其他请使用\n

ugmeyewa

ugmeyewa6#

尝试使用viex

ex -scwq foo.txt

或用于多个文件:

vi -es +"bufdo wq" *.txt
ex -s +"bufdo wq" *.txt

它会在文件保存时在EOF处自动添加EOL。
要递归应用某些文件,请使用a new globbing option**),例如**/*.txt(通过shopt -s globstar启用)。

xmjla07d

xmjla07d7#

仅使用Bash

您可以将命令替换(删除尾随换行符)与Here String(附加换行符)一起使用:

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

如果您需要inputfileoutputfile具有相同的文件名,您有两个选项-使用sponge命令、保存到带有更多命令替换的临时变量或保存到临时文件。

使用Sed

其他人建议使用

sed '$a\' inputfile

它不会在最后一行附加任何内容。这很好,但我认为

sed '$q' inputfile

因为它在最后一行退出。或者您可以

sed -n 'p'

它使用-n来抑制输出,但使用p将其打印出来。
在任何一种情况下,sed都将修复行并添加一个换行符,至少对于GNU和BSD sed是这样。但是,我不确定POSIX是否定义了此功能。sed的一个版本可能会跳过您的行而不添加换行符,因为行定义为
由零个或多个非字符加上一个终止字符组成的序列。

iqjalb3h

iqjalb3h8#

我使用dos2unix(或对应的--newline)和--newline标志解决了这个问题。优点是这些工具可以自己检测二进制文件。我喜欢使用tail -c1的解决方案,但是预先过滤二进制文件对我来说 * 真的 * 很慢。

dos2unix --newline my_file.txt

最后,我编写了一个脚本,搜索我的项目目录,将除了*.cmd文件(CRLFunix2dos)之外的所有文件转换为LFdos2unix),并使用标志通过一次调用获得正确的换行符。

jogvjijk

jogvjijk9#

使用标准shell命令有一个很好的解决方案:

tail -c 1 file.txt | read || echo >> file.txt
  1. tail输出文件最后一个字节
  2. read将一行读入变量。如果没有指定变量,则不执行任何操作,但如果在换行符之前出现EOF,则以代码1退出。
  3. echo仅在读取失败时运行(即,如果最后一个字符不是换行符),并在file.txt后追加一个换行符

相关问题