167

是否有 Unix 命令将一些字符串数据添加到文本文件中?

就像是:

prepend "to be prepended" text.txt
4

19 回答 19

178
printf '%s\n%s\n' "to be prepended" "$(cat text.txt)" >text.txt
于 2015-01-14T18:52:44.147 回答
145
sed -i.old '1s;^;to be prepended;' inFile
  • -i如果给出任何扩展名,则将更改写入到位并进行备份。(在这种情况下,.old
  • 1s;^;to be prepended;用给定的替换字符串替换第一行的开头,;用作命令分隔符。
于 2012-05-14T17:01:01.557 回答
68

进程替换

我很惊讶没有人提到这一点。

cat <(echo "before") text.txt > newfile.txt

这可以说比公认的答案更自然(打印一些东西并将其传送到替换命令中是字典上的反直觉)。

...并劫持 ryan 上面所说的内容,sponge您不需要临时文件:

sudo apt-get install moreutils
<<(echo "to be prepended") < text.txt | sponge text.txt

编辑:看起来这在 Bourne Shell 中不起作用/bin/sh


这里字符串(仅限 zsh)

使用 here-string - <<<,您可以执行以下操作:

<<< "to be prepended" < text.txt | sponge text.txt
于 2017-03-15T22:55:23.577 回答
42

这是一种可能性:

(echo "to be prepended"; cat text.txt) > newfile.txt

您可能不会轻易绕过中间文件。

替代方案(外壳转义可能很麻烦):

sed -i '0,/^/s//to be prepended/' text.txt
于 2012-05-14T16:50:07.170 回答
22

这将用于形成输出。- 表示标准输入,通过管道从 echo 提供。

echo -e "to be prepended \n another line" | cat - text.txt

要重写文件,需要一个临时文件,因为无法通过管道返回输入文件。

echo "to be prepended" | cat - text.txt > text.txt.tmp
mv text.txt.tmp text.txt
于 2012-05-14T16:52:06.423 回答
17

如果可以替换输入文件:

笔记:

  • 这样做可能会产生意想不到的副作用,特别是可能会用常规文件替换符号链接,最终获得文件的不同权限,并更改文件的创建(出生)日期。

  • sed -i,正如约翰卫斯理王子的回答,试图至少恢复原始权限,但其他限制也适用。

这是一个使用临时文件的简单替代方案(它避免像shime 的解决方案那样将整个输入文件读入内存):

{ printf 'to be prepended'; cat text.txt; } > tmp.txt && mv tmp.txt text.txt

使用命令 ( ) 比使用子 shell ( ){ ...; ...; }稍微高效一些,如0xC0000022L 的解决方案(...; ...)

优点是:

  • 很容易控制新文本是否应直接添加到第一行,或者是否应作为新行插入(只需添加\nprintf参数中)。

  • sed解决方案不同,如果输入文件为空(0字节),它会起作用。


如果意图是在现有内容前添加一整行或多sed行(假设输入文件非空),则可以简化解决方案:

sedi函数插入整行:

使用GNU sed

# Prepends 'to be prepended' *followed by a newline*, i.e. inserts a new line.
# To prepend multiple lines, use '\n' as part of the text.
# -i.old creates a backup of the input file with extension '.old'
sed -i.old '1 i\to be prepended' inFile

也适用于 macOS / BSD 的便携式变体sed

# Prepends 'to be prepended' *followed by a newline*
# To prepend multiple lines, escape the ends of intermediate
# lines with '\'
sed -i.old -e '1 i\
to be prepended' inFile

请注意,后面的文字换行符\是必需的。


如果必须就地编辑输入文件(保留其 inode 及其所有属性):

使用古老的edPOSIX 实用程序

笔记:

  • ed总是首先将输入文件作为一个整体读入内存。

直接添加到第一行(与 一样,如果输入文件完全为空(字节)sed,这将不起作用):0

ed -s text.txt <<EOF
1 s/^/to be prepended/
w
EOF
  • -s抑制ed的状态消息。
  • 注意命令是如何ed作为多行here-document ( <<EOF\n...\nEOF) 提供的,即通过stdin默认情况下,在此类文档中执行字符串扩展(插入 shell 变量);引用开始分隔符来抑制它(例如,<<'EOF')。
  • 1使第一行成为当前行
  • 函数s对当前行执行基于正则表达式的字符串替换,如sed; 您可以在替换文本中包含文字换行符,但它们必须是\- 转义的。
  • w将结果写回输入文件(为了测试,替换w,p打印结果,不修改输入文件)。

前置一个或多个行:

与 一样sed,该i函数总是在要插入的文本中添加一个尾随换行符。

ed -s text.txt <<EOF
0 i
line 1
line 2
.
w
EOF
  • 0 i使0(文件的开头)成为当前行并开始插入模式(i);请注意,行号是1基于 - 的。
  • 以下行是要在当前行之前.插入的文本,以单独的行结束。
于 2015-05-22T03:00:45.770 回答
14

更喜欢亚当的回答

我们可以让海绵更容易使用。现在我们不需要创建一个临时文件并将其重命名为

echo -e "to be prepended \n another line" | cat - text.txt | sponge text.txt
于 2015-12-25T08:32:20.990 回答
7

可能没有内置的,但你可以很容易地编写自己的,像这样:

#!/bin/bash
echo -n "$1" > /tmp/tmpfile.$$
cat "$2" >> /tmp/tmpfile.$$
mv /tmp/tmpfile.$$ "$2"

至少是这样的……

于 2012-05-14T16:49:48.020 回答
7

另一种使用方式sed

sed -i.old '1 {i to be prepended
}' inFile

如果要添加的行是多行:

sed -i.old '1 {i\ 
to be prepended\
multiline
}' inFile
于 2014-10-06T12:48:07.710 回答
7

解决方案:

printf '%s\n%s' 'text to prepend' "$(cat file.txt)" > file.txt

请注意,这对所有类型的输入都是安全的,因为没有扩展。例如,如果你想 prepend !@#$%^&*()ugly text\n\t\n,它会起作用:

printf '%s\n%s' '!@#$%^&*()ugly text\n\t\n' "$(cat file.txt)" > file.txt

最后要考虑的部分是命令替换期间文件末尾的空格删除"$(cat file.txt)"。对此的所有解决方法都相对复杂。如果要在 file.txt 末尾保留换行符,请参见:https ://stackoverflow.com/a/22607352/1091436

于 2017-11-20T19:36:26.043 回答
6

编者注:

  • 如果输入文件恰好大于系统的管道缓冲区大小(现在通常为 64 KB),则此命令将导致数据丢失。有关详细信息,请参阅评论。

在某些情况下,前置文本可能只能从标准输入获得。然后这个组合应该起作用。

echo "to be prepended" | cat - text.txt | tee text.txt

如果要省略tee输出,请附加> /dev/null.

于 2017-08-11T01:29:57.217 回答
6

正如在 Bash(在 Ubuntu 中)中测试的那样,如果从测试文件开始;

echo "Original Line" > test_file.txt

你可以执行;

echo "$(echo "New Line"; cat test_file.txt)" > test_file.txt

或者,如果 bash 的版本对于 $() 来说太旧,您可以使用反引号;

echo "`echo "New Line"; cat test_file.txt`" > test_file.txt

并接收“test_file.txt”的以下内容;

New Line
Original Line

没有中间文件,只有 bash/echo。

于 2019-02-07T19:15:27.697 回答
2

Another fairly straight forward solution is:

    $ echo -e "string\n" $(cat file)
于 2015-07-16T14:21:53.170 回答
1

如果你喜欢 vi/vim,这可能更符合你的风格。

printf '0i\n%s\n.\nwq\n' prepend-text | ed file
于 2015-01-21T23:09:12.453 回答
1

对于希望附加一行或多行文本(带有变量甚至子shell代码)并保持其可读性和格式化的未来读者,您可能会喜欢这个:

echo "Lonely string" > my-file.txt

然后运行

cat <<EOF > my-file.txt
Hello, there!

$(cat my-file.txt)
EOF

结果cat my-file.txt

Hello, there!

Lonely string

这是有效的,因为读取my-file.txt首先发生在子shell中。我一直使用这个技巧将重要的规则附加到 Docker 容器中的配置文件中,而不是复制整个配置文件。

于 2021-06-17T21:40:50.080 回答
1
% echo blaha > blaha
% echo fizz > fizz
% cat blaha fizz > buzz
% cat buzz 
blaha
fizz
于 2021-11-14T18:57:44.080 回答
0
# create a file with content..
echo foo > /tmp/foo
# prepend a line containing "jim" to the file
sed -i "1s/^/jim\n/" /tmp/foo
# verify the content of the file has the new line prepened to it
cat /tmp/foo
于 2015-04-16T21:34:02.843 回答
0

我建议定义一个函数,然后在需要的地方导入和使用它。

prepend_to_file() { 
    file=$1
    text=$2

    if ! [[ -f $file ]] then
        touch $file
    fi

    echo "$text" | cat - $file > $file.new

    mv -f $file.new $file
}

然后像这样使用它:

prepend_to_file test.txt "This is first"
prepend_to_file test.txt "This is second"

您的文件内容将是:

This is second
This is first

我将使用这种方法来实现更改日志更新程序。

于 2018-06-21T16:43:28.843 回答
0

您可以使用 awk 轻松做到这一点

cat text.txt|awk '{print "to be prepended"$0}'
于 2021-01-27T18:39:55.840 回答