Unix 命令将文本预先添加到文件中

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

比如:

prepend "to be prepended" text.txt
104353 次浏览

也许没有什么内置的,但你可以很容易地写自己的,像这样:

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

至少这样的话..。

这是一种可能性:

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

您可能很难绕过中间文件。

备选方案(对于 shell 转义来说可能很麻烦) :

sed -i '0,/^/s//to be prepended/' text.txt

这将形成输出。-手段标准输入,这是通过管道提供从回声。

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
sed -i.old '1s;^;to be prepended;' inFile
  • -i在适当的位置写入更改,如果给定了任何扩展,则执行备份(在本例中为 .old)
  • 1s;^;to be prepended;使用 ;作为命令分隔符,用给定的替换字符串替换第一行的开头。

使用 sed的另一种方法:

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

如果要前缀的行是多行:

sed -i.old '1 {i\
to be prepended\
multiline
}' inFile
printf '%s\n%s\n' "to be prepended" "$(cat text.txt)" >text.txt

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

printf '0i\n%s\n.\nwq\n' prepend-text | ed file
# 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

如果 更换可以接受输入文件:

注:

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

  • 约翰卫斯理王子的回答一样,sed -i尝试至少还原原始权限,但其他限制也适用。

下面是 使用临时文件的简单替代方法(它避免了像 希姆的解决方案那样将整个输入文件读入内存) :

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

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

优点是:

  • 很容易控制新文本是应该直接插入到第一行,还是应该插入为 新行(只需将 \n附加到 printf参数)。

  • 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 及其所有属性) :

使用古老的 ed POSIX 实用程序:

注:

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

对于 直接放在第一行前面(和 sed一样,如果输入文件是完全空的(0字节) ,这将不起作用:

ed -s text.txt <<EOF
1 s/^/to be prepended/
w
EOF
  • -s抑制了 ed的状态信息。
  • 注意命令是如何作为多行 这里-文件(<<EOF\n...\nEOF)提供给 ed的,也就是说,通过 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的。
  • 下面的行是将 之前插入当前行的文本,以 .在自己的行中结束。

另一个相当直接的解决办法是:

    $ echo -e "string\n" $(cat file)

更喜欢亚当的 回答

我们可以使它更容易使用 海绵。现在,我们不需要创建一个临时文件并通过

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

程序替代

我很惊讶竟然没人提起这件事。

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中不起作用


Here String (zsh only)

使用 here-string-<<<,您可以:

<<< "to be prepended" < text.txt | sponge text.txt

编者按:

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

在某些情况下,预置文本可能只能从 stdin 获得。 那么这个组合就可以了。

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

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

解决方案:

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

注意,这对于所有类型的输入都是安全的,因为没有展开。例如,如果你想在 !@#$%^&*()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

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

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

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

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

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。

你可以很容易地做到这一点与 awk

cat text.txt|awk '{print "to be prepended"$0}'

问题似乎是关于在文件前面添加一个字符串,而不是文件的每一行,在这种情况下,按照 Tom Ekberg的建议,应该使用以下命令。

awk 'BEGIN{print "to be prepended"} {print $0}' text.txt

对于那些希望添加一行或多行文本(带有变量甚至子 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 容器中的配置文件,而不是复制整个配置文件。

% echo blaha > blaha
% echo fizz > fizz
% cat blaha fizz > buzz
% cat buzz
blaha
fizz

你可以使用变量

尽管这里的一串答案工作得非常好,但为了完整起见,我还是想贡献这个一行程序。至少它很容易记住,并且可能有助于某些人对 bash 的一般理解。

PREPEND="new line 1"; FILE="text.txt"; printf "${PREPEND}\n`cat $FILE`" > $FILE

在这个片段中,只需将 text.txt替换为您想要前置的文本文件,将 new line 1替换为要前置的文本。

例子

$ printf "old line 1\nold line 2" > text.txt
$ cat text.txt; echo ""
old line 1
old line 2
$ PREPEND="new line 1"; FILE="text.txt"; printf "${PREPEND}\n`cat $FILE`" > $FILE
$ cat text.txt; echo ""
new line 1
old line 1
old line 2
$

有了 ex,

ex - $file << PREPEND
-1
i
prepended text
.
wq
PREPEND

ex命令是

  • 转到文件的开头
  • 开始插入模式
  • 结束插入模式
  • 保存(写)并退出