shell一个衬班要添加到文件

时间:2020-03-05 18:50:48  来源:igfitidea点击:

这可能是一个复杂的解决方案。

我正在寻找一个像">>"这样的简单操作员,而是为了预先补习。

我担心它不存在。
我必须做一些这样的事情

mv myfile tmp
 cat myheader tmp > myfile

更聪明的是什么?

解决方案

这仍然使用临时文件,但至少它是一行:

echo "text" | cat - yourfile > /tmp/out && mv /tmp/out yourfile

Credit:Bash:将文本/行添加到文件中

没有临时文件,但在这里不可能是一个oneliner

{ echo foo; cat oldfile; } > newfile && mv newfile oldfile

我们可以使用其他工具,例如ed或者perl,而不是临时文件。

如果我们在Bash中脚本,实际上,我们可以签发:

cat - yourfile  /tmp/out && mv /tmp/out yourfile

这实际上是我们自己在我们自己的问题中发布的复杂示例。

值得注意的是,它通常是使用MKTEMP等实用程序安全地生成临时文件的好主意,至少如果脚本将被用root权限执行。

例如,我们可以执行以下操作(再次在Bash中):

(tmpfile=`mktemp` && { echo "prepended text" | cat - yourfile > $tmpfile && mv $tmpfile yourfile; } )

当我们开始尝试在Shell脚本中进行困难的事情时,我将强烈建议在"正确"脚本语言(Python / Perl / Ruby / etc)中重写脚本

至于将一行提前输入文件,通过管道无法执行此操作,就像我们这样做的任何像'CAT BLAH.TXT时grep something> blah.txt',它无意中为文件空白。
有一个名为'海绵'的小实用程序命令,我们可以安装(我们做'cat blah.txt | grep something | sponge blah.txt',它缓冲了文件的内容,然后将其写入文件)。
它类似于临时文件,但我们不必明确执行此操作。
但我会说这是一个"更糟糕的"的要求,而不是说Perl。

可能有一种方法可以通过awk或者类似,但如果你必须使用shell脚本,我认为一个临时文件是迄今为止最简单的(/只?
)方式。

下面的黑客是一个快速的袖口答案,工作和接受了许多升值。
然后,由于问题变得更加流行,更多的时间通过,愤怒的人开始报告它的工作,但奇怪的事情可能发生,或者它只是没有工作,所以这是一段时间疯狂地下降。
好好玩。

该解决方案利用系统上的文件描述符的精确实现,因为在NIXE之间的实施中的实现显着变化,这取得了成功,完全是系统依赖性,绝对不便携的,并且不应该依靠模糊不可依赖的。

现在,答案的所有方式都是:

创建文件的另一个文件描述符('exec 3 <> yourfile'),从那时写入('>&3')似乎克服了同一文件困境的读/写。
用扶手上的600k文件为我工作。
然而,使用"猫"失败尝试同样的伎俩。

将Prependage作为变量传递给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

假设要编辑的文件是my.txt

$cat my.txt    
this is the regular file

我们要预付的文件是标题

$ 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'工作。

CB0的一个变体为"NO TEMP文件"的解决方案中的解决方案,以预先修复修复文本:

echo "text to prepend" | cat - file_to_be_modified | ( cat > file_to_be_modified )

这再次依赖于子shell执行(..),以避免拒绝具有相同的输入和输出的文件。

注意:喜欢此解决方案。
但是,在我的Mac中,原始文件丢失(认为它不应该但它不应该)。
这可以通过将解决方案写作:
echo"prepend文本"| cat file_to_be_modified |猫> tmp_file; mv tmp_file file_to_be_modified.

呸!没有人关心tac。

endor@grid ~ $ tac --help
Usage: tac [OPTION]... [FILE]...
Write each FILE to standard output, last line first.
With no FILE, or when FILE is -, read standard input.
Mandatory arguments to long options are mandatory for short options too.
  -b, --before             attach the separator before instead of after
  -r, --regex              interpret the separator as a regular expression
  -s, --separator=STRING   use STRING as the separator instead of newline
      --help     display this help and exit
      --version  output version information and exit
Report tac bugs to [email protected]
GNU coreutils home page: <http://www.gnu.org/software/coreutils/>
General help using GNU software: <http://www.gnu.org/gethelp/>
Report tac translation bugs to <http://translationproject.org/team/>

current=`cat my_file` && echo 'my_string' > my_file && echo $current >> my_file

其中"my_file"是将"my_string"添加到的文件。

John Mee:方法无法保证工作,如果我们预先添加了超过4096个字节的东西(至少是GNU AWK发生的事情,但我认为其他实现将具有类似的约束)。
在这种情况下,它不仅会失败,而且它将进入一个无休止的循环,在那里它将读取自己的输出,从而使文件增长,直到填充所有可用空间。

为自己试试:

exec 3<>myfile && awk 'BEGIN{for(i=1;i<=1100;i++)print i}{print}' myfile >&3

(警告:在一段时间后杀死它,或者它将填充文件系统)

此外,编辑文件是非常危险的,这是非常糟糕的建议,好像在编辑文件时发生某些东西(崩溃,磁盘满),我们几乎保证以不一致的状态留下文件。

echo '0a
your text here
.
w' | ed some_file

ed是标准编辑器! http://www.gnu.org/fun/jokes/ed.msg.html.

sed -i -e "1s/^/new first line\n/" old_file.txt

编辑:这是破碎的。
准备好猫和多特群的文件时,请参阅奇怪行为

覆盖问题的解决方法使用"TEE":

cat header main | tee main > /dev/null

警告:这需要更多的工作来满足OP的需求。

尽管他的疑虑,应该有一种方法可以通过@shixilun制作SED方法。
必须有一个bash命令在将文件读入sed替换字符串时逃脱空格(例如,用'\ 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的可怕缓冲区溢出问题。

为什么不仅仅是使用ED命令(如图所示的垃圾)?

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 "" . wq | ed -s ""
}
echo 'Hello, world!' > myfile
prepend 'line to prepend' myfile

另一个解决方法将使用J眉RGENHH?
Tzel从Sed'S / C / D / 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

当然,这一切都可以放在一行上。

我使用的那个。
这一个允许我们以我们喜欢的方式指定订单,额外的字符等:

echo -e "TEXTFIRSt\n$(< header)\n$(< my.txt)" > my.txt

P.S:如果文件包含Backslash的文本,则才能运行,导致它被解释为转义字符

我喜欢@ fluffle的ed方法是最好的。

毕竟,任何工具的命令行交换机与脚本编辑器命令在此处基本上是相同的;没有看到脚本的编辑器解决方案"清洁"是任何较小的或者何时。

这是我的一班林添加到'.git / hooks / prepare-commm-msg'以预先提交in-repo'.gitmessage'文件来提交消息:

echo -e "1r $PWD/.gitmessage\n.\nw" | ed -s ""

示例'.gitmessage':

# Commit message formatting samples:
#       runlevels: boot +consolekit -zfs-fuse
#

我正在做'1R'而不是'0R',因为这将从原始模板上留下文件顶部的空现代写入线。
不要在'.gitmessage'之上放置一个空线,你将最终有两个空线。
'-s'抑制ed的诊断信息输出。

与越来越通过这个,我发现对于Vim-Buff,它也很好:

[core]
        editor = vim -c ':normal gg'

变量,ftw?

NEWFILE=$(echo deb http://mirror.csesoc.unsw.edu.au/ubuntu/ $(lsb_release -cs) main universe restricted multiverse && cat /etc/apt/sources.list)
echo "$NEWFILE" | sudo tee /etc/apt/sources.list

这是我发现的:

echo -e "header \n$(cat file)" >file

像Daniel Velkov建议,使用T恤。

对我来说,这是简单的智能解决方案:

{ echo foo; cat bar; } | tee bar > /dev/null

sed -i -e '1rmyheader' -e '1{h;d}' -e '2{x;G}' myfile

我认为这是ED的最新变化:

cat myheader | { echo '0a'; cat ; echo -e ".\nw";} | ed myfile

作为一个功能:

function prepend() { { echo '0a'; cat ; echo -e ".\nw";} | ed ; }
cat myheader | prepend myfile

如果我们在控制的计算机上需要它,请安装"moututils"包并使用"海绵"。
然后你可以做:

cat header myfile | sponge myfile

主要是为了有趣/贝壳高尔夫,但是

ex -c '0r myheader|x' myfile

将做诀窍,没有管道或者重定向。
当然,VI / EX并不是真正的非交互式使用,因此VI将简要闪烁。

使用$(命令),我们可以将命令的输出写入变量。

所以我在一行中的三个命令中完成了它,没有临时文件。

originalContent=$(cat targetfile) && echo "text to prepend" > targetfile && echo "$originalContent" >> targetfile

imho没有shell解决方案(并且永远不会是一个),这将一致地和可靠地工作,无论两个文件'myheader'和'myfile'的大小。
原因是,如果我们想在不重新定位到临时文件的情况下(而不让Shell默默地默认到临时文件的情况下,例如,通过像'EXEC 3 <> MYFILE',管道为'TEE'等)。

我们正在寻找的"真实"解决方案需要小提琴与文件系统,因此它在用户空间中没有可用,并且将依赖于平台:我们要求在使用"myfile"的当前值时修改文件系统指针"MyHeader"的文件系统指针并替换为"MyHeader"的"eof"的文件系统,其中包含"MyFile"指向当前文件系统地址的链接。
这并不是微不足道的,显然不能由非超级用户完成,并且可能不是超级用户......与in inode等。

但是,我们可以使用循环设备或者多或者少地伪造这一点。
看上来这么好。

如果我们有一个大文件(在我的情况下几百千字节)并访问Python,那么这比"猫"的管道解决方案更快:

'python -c'f ="filename"; t =打开(f).read();打开(f,"w")。
写("要预付"文本"+ T)''

使用Bash Heredoc,我们可以避免需要TMP文件:

cat <<-EOF > myfile
  $(echo this is prepended)
  $(cat myfile)
EOF

这是因为在评估Bash脚本时评估了$(CAT MyFile),在执行重定向时进行评估。

快速且脏,缓冲与python内存中的所有内容:

$ echo two > file
$ echo one | python -c "import sys; f=open(sys.argv[1]).read(); open(sys.argv[1],'w').write(sys.stdin.read()+f)" file
$ cat file
one
two
$ # or creating a shortcut...
$ alias prepend='python -c "import sys; f=open(sys.argv[1]).read(); open(sys.argv[1],\"w\").write(sys.stdin.read()+f)"'
$ echo zero | prepend file
$ cat file
zero
one
two

具有"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}"

但在这种情况下,我们必须确保在任何地方不得不在那里,包括目标文件的内容,因为可以解释并搞定结果。

我们可以使用Perl命令行:

perl -i -0777 -pe 's/^/my_header/' tmp

其中-i将创建文件的内联替换文件
-0777将啜饮整个文件并使^仅匹配开头。

-pe将打印所有的行

或者如果my_header是文件:

perl -i -0777 -pe 's/^/`cat my_header`/e' tmp

/ E将允许替换中的代码评估。