【问题标题】:How to insert a text at the beginning of a file?如何在文件开头插入文本?
【发布时间】:2012-03-20 23:29:31
【问题描述】:

到目前为止,我已经知道如何在文件开头添加一行,但这并不是我想要的。我会用一个例子来展示它:

文件内容

some text at the beginning

结果

<added text> some text at the beginning

很相似,但我不想用它创建任何新行...

如果可能的话,我想用sed 来做这件事。

【问题讨论】:

标签: linux bash sed


【解决方案1】:

我找到的最简单的解决方案是:

echo -n "<text to add>" | cat - myFile.txt | tee myFile.txt

注意事项:

  • 如果您不想更改文件内容,请删除 | tee myFile.txt
  • 如果要附加整行,请删除 -n 参数。
  • 如果您不想看到输出(生成的文件),请将&amp;&gt; /dev/null 添加到末尾。
  • 这可用于将 shebang 附加到文件中。例子:
    # make it executable (use u+x to allow only current user)
    chmod +x cropImage.ts
    # append the shebang
    echo '#''!'/usr/bin/env ts-node | cat - cropImage.ts | tee cropImage.ts &> /dev/null
    # execute it
    ./cropImage.ts myImage.png
    

【讨论】:

  • 这会在同一行中添加两次文本
  • 它也替换了整个文件的内容。
  • @DavidHeisnam,是的,它会替换文件,除非您移除三通管(我已经更新了答案)。但它不会两次附加文本。您可能已运行该命令两次。它在 bash 和 zsh 中工作。
【解决方案2】:

使用子shell:

echo "$(echo -n 'hello'; cat filename)" > filename

不幸的是,命令替换将删除文件末尾的换行符。为了让他们可以使用:

echo -n "hello" | cat - filename > /tmp/filename.tmp
mv /tmp/filename.tmp filename

既不需要分组也不需要命令替换。

【讨论】:

  • 此解决方案删除文件末尾的空行
  • 对于所有其他使用 sed 的解决方案来说,这是一个更优越、更简单的解决方案,它不适用于空文件。
  • @dafnahaktana 那是因为命令替换
【解决方案3】:

使用echo 方法,如果您像我一样使用macOS/BSD,请不要使用其他人建议的-n 开关。我喜欢为文本定义一个变量。

所以应该是这样的:

Header="my complex header that may have difficult chars \"like these quotes\" and line breaks \n\n "

{ echo "$Header"; cat "old.txt"; } > "new.txt"
mv new.txt old.txt

【讨论】:

    【解决方案4】:

    另一个使用别名的解决方案。添加到您的 init rc/env 文件中:

    addtail () { find . -type f ! -path "./.git/*" -exec sh -c "echo $@ >> {}" \; }
    addhead () { find . -type f ! -path "./.git/*" -exec sh -c  "sed -i '1s/^/$@\n/' {}" \; }
    

    用法:

    addtail "string to add at the beginning of file"
    addtail "string to add at the end of file"
    

    【讨论】:

      【解决方案5】:

      我的两分钱:

      sed  -i '1i /path/of/file.sh' filename
      

      即使是包含正斜杠"/"的字符串也可以使用

      【讨论】:

        【解决方案6】:

        只是为了好玩,这里有一个使用ed 的解决方案,它不存在无法处理空文件的问题。您可以将其放入 shell 脚本中,就像此问题的任何其他答案一样。

        ed Test <<EOF
        a
        
        .
        0i
        <added text>
        .
        1,+1 j
        $ g/^$/d
        wq
        EOF
        

        上面的脚本将要插入的文本添加到第一行,然后连接第一行和第二行。为了避免 ed 因无效连接出错而退出,它首先在文件末尾创建一个空行,如果它仍然存在,稍后将其删除。

        限制:如果&lt;added text&gt; 正好等于单个句点,则此脚本不起作用。

        【讨论】:

          【解决方案7】:

          问题:在文件顶部用父目录的基本名称标记文件。

          即,对于

          /mnt/Vancouver/Programming/file1
          

          Programming标记file1的顶部。

          解决方案 1 -- 非空文件:

          bn=${PWD##*/}    ## bn: basename
          
          sed -i '1s/^/'"$bn"'\n/' <file>
          

          1s 将文本放在文件的第 1 行。

          解决方案 2 -- 空文件或非空文件:

          上面的sed 命令在处理空文件时失败。这是一个解决方案,基于https://superuser.com/questions/246837/how-do-i-add-text-to-the-beginning-of-a-file-in-bash/246841#246841

          printf "${PWD##*/}\n" | cat - <file> > temp && mv -f temp <file>
          

          请注意,cat 命令中的- 是必需的(读取标准输入:有关更多信息,请参阅man cat)。在这里,我相信,需要将 printf 语句的输出(到 STDIN),并将该文件和文件放入 temp ... 另见 http://www.linfo.org/cat.html 底部的解释。

          我还在mv 命令中添加了-f,以避免在覆盖文件时被要求确认。

          递归目录:

          for file in *; do printf "${PWD##*/}\n" | cat - $file > temp && mv -f temp $file; done
          

          还要注意,这会用空格分隔路径;在其他地方有解决方案(例如文件通配,或 find . -type f ... 类型的解决方案)。

          ADDENDUM: Re:我的最后一条评论,此脚本将允许您递归遍历路径中带有空格的目录:

          #!/bin/bash
          
          ## https://stackoverflow.com/questions/4638874/how-to-loop-through-a-directory-recursively-to-delete-files-with-certain-extensi
          
          ## To allow spaces in filenames,
          ##   at the top of the script include: IFS=$'\n'; set -f
          ##   at the end of the script include: unset IFS; set +f
          
          IFS=$'\n'; set -f
          
          # ----------------------------------------------------------------------------
          # SET PATHS:
          
          IN="/mnt/Vancouver/Programming/data/claws-test/corpus test/"
          
          # https://superuser.com/questions/716001/how-can-i-get-files-with-numeric-names-using-ls-command
          
          # FILES=$(find $IN -type f -regex ".*/[0-9]*")        ## recursive; numeric filenames only
          FILES=$(find $IN -type f -regex ".*/[0-9 ]*")         ## recursive; numeric filenames only (may include spaces)
          
          # echo '$FILES:'                                      ## single-quoted, (literally) prints: $FILES:
          # echo "$FILES"                                       ## double-quoted, prints path/, filename (one per line)
          
          # ----------------------------------------------------------------------------
          # MAIN LOOP:
          
          for f in $FILES
          do
          
            # Tag top of file with basename of current dir:
            printf "[top] Tag: ${PWD##*/}\n\n" | cat - $f > temp && mv -f temp $f
          
            # Tag bottom of file with basename of current dir:
            printf "\n[bottom] Tag: ${PWD##*/}\n" >> $f
          done
          
          unset IFS; set +f
          

          【讨论】:

            【解决方案8】:

            有一个非常简单的方法:

            echo "your header" > headerFile.txt
            cat yourFile >> headerFile.txt
            

            【讨论】:

            • 哦...抱歉,现在我意识到您想在开头添加而不是新行。
            • 但是想要换行。所以感谢您提供的简单方法。
            【解决方案9】:

            sed 可以对地址进行操作:

            $ sed -i '1s/^/<added text> /' file
            

            您在此处的每个答案中看到的这个神奇的1s 是什么? Line addressing!.

            想要在前 10 行添加&lt;added text&gt;

            $ sed -i '1,10s/^/<added text> /' file
            

            或者你可以使用Command Grouping:

            $ { echo -n '<added text> '; cat file; } >file.new
            $ mv file{.new,}
            

            【讨论】:

            • 实际插入新行:sed -i '1s/^/ \n/' file
            • 为什么要使用 -i ??在 man 它说它是后缀。 linux.die.net/man/1/sed
            • -i 代表就地,您可以在 -i 后附加一个后缀来进行复制而不是覆盖。 -i.new 会创建一个以 .new 结尾的新文件,但 -i 会直接编辑该文件。
            • 请注意,sed 不能在空文件上工作 - afaict sed 根本无法使用 0 长度输入来执行任何操作。
            • 这个解决方案的缺陷是文件为空时不添加文本。
            【解决方案10】:

            在文件顶部添加一行:

            sed -i '1iText to add\'
            

            【讨论】:

            • 这包括一个换行符,这是提问者明确不想要的。
            【解决方案11】:

            只插入一个换行符:

            sed '1i\\'
            

            【讨论】:

            • 我想知道为什么票数最高的答案都使用 s 而不是 i。这有什么缺点吗?
            • @Caesar 因为当你只有一把锤子时,每个问题看起来都像钉子。
            【解决方案12】:

            请注意,在 OS X 上,sed -i &lt;pattern&gt; file 会失败。但是,如果您提供备份扩展名sed -i old &lt;pattern&gt; file,则在创建file.old 时会原地修改file。然后,您可以在脚本中删除 file.old

            【讨论】:

            • 或 sed -i '' 文件。然后它只会就地编辑而不进行备份。
            • 我发现 macOS sed 希望在不创建备份的情况下就地编辑一个点:sed -i。 文件
            【解决方案13】:
            echo -n "text to insert " ;tac filename.txt| tac > newfilename.txt
            

            第一个tac 向后管道传输文件(最后一行在前),因此“要插入的文本”出现在最后。第二个tac 再次包装它,因此插入的行位于开头,原始文件按其原始顺序排列。

            【讨论】:

            • 您能否解释一下这将如何帮助 Tomas 解决这个问题?
            • tac | tac -- 这就是不可扩展的思维模式的形成方式:-(
            【解决方案14】:

            您可以使用cat -

            printf '%s' "some text at the beginning" | cat - filename
            

            【讨论】:

            • 这只会输出文件内容后面的文本,但根本不会修改文件。
            • 这是一个很好的解决方案,我想知道为什么它没有得到任何支持。这是我的好先生。另外,为什么 printf 而不是简单的 echo ?
            • @ychaouche - 大概是因为没有可移植的方法来阻止 echo 添加换行符?
            • 我尝试通过将&gt; file 附加到命令来将其定向到文件中,它只是用"some text at the beginning" 向我的终端发送垃圾邮件
            • printf '%s' "some text" | cat - filename &gt; tmpfile &amp;&amp; mv tmpfile filename
            【解决方案15】:

            如果要在文件的开头添加一行,则需要在上面的最佳解决方案中的字符串末尾添加\n

            最好的解决方案是添加字符串,但是有了字符串,它不会在文件末尾添加一行。

            sed -i '1s/^/your text\n/' file
            

            【讨论】:

            • 在 Mac OS 上,出现“未定义标签”错误。发现需要给备份文件一个扩展名;见mkyong.com/mac/…
            • 在 Mac OS 的sed 版本下,您必须提供带有-i 选项的备份文件名。可以只传递一个空字符串而不进行备份,例如 sed -i '' '1s/^/new test\n/' filename
            【解决方案16】:

            你好,回车:

            sed -i '1s/^/your text\n/' file
            

            【讨论】:

              【解决方案17】:

              如果文件只有一行,可以使用:

              sed 's/^/insert this /' oldfile > newfile
              

              如果超过一行。之一:

              sed '1s/^/insert this /' oldfile > newfile
              sed '1,1s/^/insert this /' oldfile > newfile
              

              我已经包含了后者,以便您知道如何处理行范围。这两个都将受影响行上的起始行标记“替换”为您要插入的文本。您还可以(假设您的 sed 足够现代)使用:

              sed -i 'whatever command you choose' filename
              

              进行就地编辑。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2018-01-04
                • 2010-09-11
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多