【问题标题】:Add a newline only if it doesn't exist仅在不存在时添加换行符
【发布时间】:2012-04-22 08:34:08
【问题描述】:

我只想在文件不存在的情况下在文件末尾添加换行符。这是为了防止文件末尾出现多个换行符。

我希望使用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

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

【问题讨论】:

标签: linux bash sed newline


【解决方案1】:

sed

GNU:

sed -i '$a\' *.txt

操作系统:

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 可以替换为任何计算结果为真的东西。就地修改文件:

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

重击

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

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

【讨论】:

  • 整洁点! $\a 公式不起作用(在 Mac 上),但 -n p 公式起作用了……但它是如何工作的?
  • 嗯,实际上,在 ubuntu bash 上试用它们,都返回错误 sed: can't read p: No such file or directory
  • 我编辑了答案。它应该是sed '$a\'。显然 -i '' 不适用于 GNU sed。
  • sed -i '$a\' &lt;files&gt; 在 Ubuntu 上非常适合我。谢谢!
  • GNU 解决方案在 OS X El Capitan (10.11) 上运行良好。
【解决方案2】:

而不是使用 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

【讨论】:

  • 很好很干净,因为它只需要 tail 和 echo,而不是 sed 或 awk。
【解决方案3】:

如果它不存在,它会删除换行符,您可以简单地使用:

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

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

【讨论】:

  • echo "" &gt;&gt; file; 添加换行符; sed -ie '/^$/d;$G' file; 删除换行符?并再次应用相同的代码?编辑:它当然有效,但我认为必须有一个更整洁的方法..:P
【解决方案4】:
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/

【讨论】:

  • 这是ansible中唯一对我有用的解决方案
【解决方案5】:

使用 awk :

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

匹配空行^$(就像你做的那样)并设置一个标志。如果最后没有设置标志,则放置换行符。

注意:\r 在 OS X 中。其他使用 \n

【讨论】:

    【解决方案6】:

    尝试使用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启用)。

    【讨论】:

      【解决方案7】:

      仅使用 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
      

      如果您需要 inputfileoutputfile 是相同的文件名,您有几个选择 - 使用 sponge 命令,保存到临时变量并替换更多命令,或者保存到临时文件。


      使用 Sed

      其他人建议使用

      sed '$a\' inputfile
      

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

      sed '$q' inputfile
      

      更清楚一点,因为它在最后一行退出。或者你可以这样做

      sed -n 'p'
      

      它使用-n 抑制输出,但使用p 将其打印出来。

      在任何这些情况下,sed 将修复该行并添加一个换行符,至少对于 GNU 和 BSD sed。但是,我不确定此功能是否由 POSIX 定义。 sed 的一个版本可能只是跳过你的行而没有换行,因为一行被定义为

      A sequence of zero or more non- characters plus a terminating character.

      【讨论】:

        【解决方案8】:

        我通过使用带有--newline 标志的dos2unix(或对应物)解决了这个任务。优点是这些工具可以自行检测二进制文件。我喜欢tail -c1 的解决方案,但事先过滤二进制文件对我来说真的很慢。

        dos2unix --newline my_file.txt
        

        最终我编写了一个脚本来搜索我的项目目录,将所有文件转换为 LF (dos2unix) 除了 *.cmd 文件 (CRLF, unix2dos) 并使用标志来获取换行符一个电话。

        【讨论】:

        • 我已经测试了该命令,但不知何故它不起作用(至少在 OS X 上)。测试:printf foo &gt; foo.txt &amp;&amp; dos2unix --newline foo.txt &amp;&amp; wc foo.txt 这给了我0 1 3 这是不正确的。
        • 我可以确认这在 Debian Linux 上不起作用。我记得当时在 Cygwin 中成功地做到了这一点。
        猜你喜欢
        • 1970-01-01
        • 2014-01-05
        • 2016-07-02
        • 2018-02-12
        • 1970-01-01
        • 2013-04-15
        • 2015-01-11
        • 2016-10-19
        • 2012-03-08
        相关资源
        最近更新 更多