这可能是一个复杂的解决方案。
我正在寻找一个简单的运算符,例如“ >>”,但要放在前面。
恐怕它不存在。我必须做类似的事情
mv myfile tmp 猫myheader tmp> myfile
还有什么更聪明的吗?
这可能是一个复杂的解决方案。
我正在寻找一个简单的运算符,例如“ >>”,但要放在前面。
恐怕它不存在。我必须做类似的事情
mv myfile tmp 猫myheader tmp> myfile
还有什么更聪明的吗?
Answers:
下面的hack是一个快速的即席回答,该方法行之有效并获得了很多好评。然后,随着这个问题变得越来越流行和更多的时间流逝,愤怒的人们开始报告说这个问题确实有效,但是奇怪的事情可能会发生,或者根本不起作用,所以一度被人们低估了。好好玩。
该解决方案利用了系统上文件描述符的确切实现,并且由于实现之间的差异很大,因此它的成功完全取决于系统,绝对不可移植,并且即使有非常重要的意义也不应依赖于此。
现在,有了所有这些答案,答案是:
为文件(exec 3<> yourfile
)创建另一个文件描述符,然后写入该文件()>&3
似乎可以解决对同一文件的读写难题。使用awk为我处理600K文件。但是,使用“ cat”尝试相同的技巧失败。
将前置变量作为变量传递给awk(-v TEXT="$text"
)可以解决文字引号问题,该问题阻止了使用“ sed”实现此技巧。
#!/bin/bash
text="Hello world
What's up?"
exec 3<> yourfile && awk -v TEXT="$text" 'BEGIN {print TEXT}{print}' yourfile >&3
这仍然使用一个临时文件,但至少它在一行上:
echo "text" | cat - yourfile > /tmp/out && mv /tmp/out yourfile
-
之后在做什么cat
?
echo -n "text"
yourfile
是符号链接,则不会执行您想要的操作。
echo '0a
your text here
.
w' | ed some_file
0r header.file
echo -e '0a\nyour text here\n.\nw' | ed some_file
约翰·米(John Mee):您的方法不能保证能正常工作,并且如果您将4096字节以上的内容添加到前面,可能会失败(至少gnu awk会发生这种情况,但我想其他实现将具有类似的约束)。在这种情况下,它不仅会失败,而且将进入一个无限循环,在循环中它将读取自己的输出,从而使文件增长,直到所有可用空间都被填满。
自己尝试:
exec 3<>myfile && awk 'BEGIN{for(i=1;i<=1100;i++)print i}{print}' myfile >&3
(警告:过一会儿杀死它,否则它将填满文件系统)
此外,以这种方式编辑文件非常危险,这是非常糟糕的建议,因为似乎在编辑文件时发生了某些情况(崩溃,磁盘已满),几乎可以保证文件处于不一致状态。
没有临时文件是不可能的,但是这里有一个单面纸
{ echo foo; cat oldfile; } > newfile && mv newfile oldfile
您可以使用ed或perl等其他工具来执行此操作,而无需使用临时文件。
如果需要在您控制的计算机上安装此软件包,请安装软件包“ moreutils”并使用“海绵”。然后,您可以执行以下操作:
cat header myfile | sponge myfile
{ echo "prepended text"; cat myfile } | sponge myfile
假设您要编辑的文件是my.txt
$cat my.txt
this is the regular file
您要添加的文件是header
$ cat header
this is the header
确保头文件中有最后一个空行。
现在,您可以添加
$cat header <(cat my.txt) > my.txt
你最终得到
$ cat my.txt
this is the header
this is the regular file
据我所知,这仅适用于“ bash”。
this is the header
在my.txt中输入了两行。即使我将Bash更新4.3.42(1)-release
为相同的结果。
<(...)
)中的命令将写入该FIFO(管道),因此无法保证必须my.txt
预先读取所有内容,否则,该技术将无法工作。
当您开始尝试使用shell脚本进行困难的事情时,我强烈建议您尝试使用“适当的”脚本语言(Python / Perl / Ruby / etc)重写脚本
至于在文件前添加一行,则无法通过管道执行此操作,因为当您执行时cat blah.txt | grep something > blah.txt
,它会无意中使文件空白。sponge
您可以安装一个小的实用程序命令(您可以安装该命令,该命令cat blah.txt | grep something | sponge blah.txt
会缓冲文件的内容,然后将其写入文件中)。它类似于临时文件,但您不必显式地执行该操作。但是我想说,这比Perl更为“糟糕”。
也许有一种方法可以通过awk或类似的方法来完成,但是如果您必须使用shell脚本,我认为临时文件是迄今为止最简单的(/仅?)方法。
为什么不简单使用ed命令(如fluffle此处已建议的那样)?
ed将整个文件读入内存并自动执行就地文件编辑!
所以,如果您的文件不是那么大...
# cf. "Editing files with the ed text editor from scripts.",
# http://wiki.bash-hackers.org/doku.php?id=howto:edit-ed
prepend() {
printf '%s\n' H 1i "${1}" . wq | ed -s "${2}"
}
echo 'Hello, world!' > myfile
prepend 'line to prepend' myfile
另一个变通办法是按照JürgenHötzel在将sed's / c / d /'myFile重定向到myFile的输出重定向中的建议使用打开文件句柄。
echo cat > manipulate.txt
exec 3<manipulate.txt
# Prevent open file from being truncated:
rm manipulate.txt
sed 's/cat/dog/' <&3 > manipulate.txt
当然,所有这些都可以放在一行上。
cb0解决方案的一个变体,用于“无临时文件”以添加固定文本:
echo "text to prepend" | cat - file_to_be_modified | ( cat > file_to_be_modified )
再次,这依赖于子外壳程序的执行(..),以避免猫拒绝输入和输出相同的文件。
注意:喜欢此解决方案。但是,在我的Mac中,原始文件丢失了(认为它不应该,但是会丢失)。可以通过将解决方案编写为以下内容来解决该问题:echo“ text to prepend” | 猫-file_to_be_modified | 猫> tmp_file; mv tmp_file file_to_be_modified
警告:这需要做更多的工作才能满足OP的需求。
尽管有@shixilun的担忧,但应该有一种方法可以使@shixilun的sed方法起作用。将文件读入sed替代字符串时,必须有一个bash命令来转义空格(例如,用'\ n'替换换行符。Shell命令vis
并且cat
可以处理不可打印的字符,但不能处理空格,因此这不能解决OP的问题问题:
sed -i -e "1s/^/$(cat file_with_header.txt)/" file_to_be_prepended.txt
由于替换脚本中的原始换行而失败,该脚本需要在换行符之前加上换行符(),并可能在后面加上&,以使shell和sed保持满意,就像这样的答案
sed
对于非全局搜索替换命令,其大小限制为40K(模式后无尾随/ g),因此可以避免匿名警告的可怕的awk缓冲区溢出问题。
解决方案printf
:
new_line='the line you want to add'
target_file='/file you/want to/write to'
printf "%s\n$(cat ${target_file})" "${new_line}" > "${target_file}"
您也可以这样做:
printf "${new_line}\n$(cat ${target_file})" > "${target_file}"
但是在那种情况下,您必须确保没有任何%
地方,包括目标文件的内容,因为这可以解释并弄乱您的结果。
echo
似乎是一个更安全的选择。echo "my new line\n$(cat my/file.txt)" > my/file.txt
${new_line}
了目标文件中的百分比,而不是目标文件中的百分比
我最喜欢@fluffle的ed方法。毕竟,任何工具的命令行开关与脚本编辑器命令在本质上都是相同的。没有看到脚本化的编辑器解决方案“整洁度”要小得多或什么都没有。
这是我的一句话,附加到.git/hooks/prepare-commit-msg
内部repo .gitmessage
文件中以提交消息:
echo -e "1r $PWD/.gitmessage\n.\nw" | ed -s "$1"
范例.gitmessage
:
# Commit message formatting samples:
# runlevels: boot +consolekit -zfs-fuse
#
我正在1r
代替0r
,因为这将在原始模板中的文件顶部保留空的可写行。.gitmessage
然后,不要在上面加上空行,最后将得到两条空行。-s
抑制ed的诊断信息输出。
关于这一点,我发现对于vim-buffs来说,拥有以下内容也是一件好事:
[core]
editor = vim -c ':normal gg'
恕我直言,没有shell解决方案(并且永远不会是一个解决方案),无论两个文件myheader
和的大小如何,它都可以一致且可靠地工作myfile
。原因是,如果您要执行此操作,而无需重复使用临时文件(并且不让Shell静默地重复使用临时文件,例如通过exec 3<>myfile
,管道传输到tee
等结构)。
您正在寻找的“实际”解决方案需要摆弄文件系统,因此它在用户空间中不可用,并且将依赖于平台:您正在要求将使用中的文件系统指针修改为文件系统指针myfile
的当前值。对于myheader
和替换在文件系统中EOF
的myheader
一个链接的链接通过指出当前的文件系统地址myfile
。这并非易事,而且非超级用户显然也无法做到,而且超级用户也可能无法做到这一点……使用inode,等等。
不过,您可以使用环路设备或多或少地伪造此内容。例如参见此SO线程。
mktemp
?之后,您始终可以清理临时文件...