ChatGPT解决这个技术问题 Extra ChatGPT

如何在文件开头插入文本?

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

文件内容

some text at the beginning

结果

<added text> some text at the beginning

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

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

这里有什么适合你的吗? stackoverflow.com/questions/54365/… - 您不需要使用 sed

C
Cy Rossignol

sed 可以对地址进行操作:

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

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

想要在前 10 行添加 <added text>

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

或者您可以使用 Command Grouping

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

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

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

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

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

在 Mac OS 上,出现“未定义标签”错误。发现需要给备份文件一个扩展名;见mkyong.com/mac/…
在 Mac OS 的 sed 版本下,您必须提供带有 -i 选项的备份文件名。一个人可以只传递一个空字符串而没有像 sed -i '' '1s/^/new test\n/' filename 这样的备份
p
paxdiablo

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

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

进行就地编辑。


N
Nick Roz

使用子外壳:

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

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

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

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


此解决方案删除文件末尾的空行
这是使用 sed 的所有其他解决方案的优越和简单的解决方案,它不适用于空文件。
@dafnahaktana 那是因为命令替换
佚名

只插入一个换行符:

sed '1i\\'

我想知道为什么投票最多的答案都使用 s 而不是 i。这有什么缺点吗?
@Caesar 因为当你只有一把锤子时,每个问题看起来都像钉子。
g
gniourf_gniourf

您可以使用 cat -

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

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

在文件顶部添加一行:

sed -i '1iText to add\'

这包括一个换行符,这是提问者明确不想要的。
v
vardhan

我的两分钱:

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

即使是包含正斜杠 "/" 的字符串,这也将起作用


x
xck

回车您好:

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

C
Curt Clifton

请注意,在 OS X 上,sed -i <pattern> file 失败。但是,如果您提供备份扩展 sed -i old <pattern> file,则在创建 file.old 的同时修改 file。然后,您可以删除脚本中的 file.old


或 sed -i '' 文件。然后它只会就地编辑而不进行备份。
我发现 macOS sed 希望在不创建备份的情况下就地编辑一个点:sed -i。 <模式> 文件
R
Raphael Villas Boas

有一个非常简单的方法:

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

哦...抱歉,现在我意识到您想在开头添加而不是新行。
但我想要一条新线。所以感谢简单的方法。
V
Victoria Stuart

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

即,对于

/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 ... 类型的解决方案)。

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

#!/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

m
merlin2011

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

ed Test <<EOF
a

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

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

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


q
qwerty_so
echo -n "text to insert " ;tac filename.txt| tac > newfilename.txt

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


你能解释一下这将如何帮助托马斯解决这个问题吗?
塔克 | tac——这就是不可扩展的思维模式的形成方式:-(
0
0x8BADF00D

另一个带有别名的解决方案。添加到您的 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"

k
kakyo

使用 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

M
Murilo Perrone

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

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

笔记:

删除 | tee myFile.txt 如果您不想更改文件内容。

如果要附加整行,请删除 -n 参数。

如果您不想看到输出(生成的文件),请将 &> /dev/null 添加到末尾。

这可用于将 shebang 附加到文件中。示例: # 使其可执行(使用 u+x 只允许当前用户) chmod +x cropImage.ts # 附加 shebang echo '#''!'/usr/bin/env ts-node |猫-cropImage.ts | tee cropImage.ts &> /dev/null # 执行 ./cropImage.ts myImage.png


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

TL;博士-

考虑使用 ex。由于您想要给定行的前面,因此语法与 sed 的语法基本相同,但“就地编辑”选项是内置的。

我无法想象你有 sed 但没有 ex/vi 的环境,除非它是一个带有一些特殊“sed.exe”的 MS Windows 机器,也许。

sed & grepex / vi 演变而来,因此最好说 sed 语法与 ex 相同。

您可以将行号更改为 #1 之外的其他内容,或者搜索一行并更改该行。

source=myFile.txt
Front="This goes IN FRONT "
man true > $source
ex -s ${source} <<EOF
1s/^/$Front/ 
wq
EOF
$ head -n 3 $source
This goes IN FRONT TRUE(1)                                                    User Commands                                                    TRUE(1)

NAME

长版,我推荐 ex(如果您是酷孩子之一,则推荐 ed)。

我喜欢 ex,因为它是可移植的、非常强大的,允许我就地编写和/或进行备份,而无需 GNU(甚至 BSD)扩展。

此外,如果您知道 ex 方式,那么您就知道如何在 vi 中执行它 - 如果那是您的难题,可能还有 vim

source=myFile.txt
topString="******  This goes on TOP  ******"
man true > "$source"
ex -s ${source} <<-EOF
0r!echo "$topString"
wq
EOF

0r 是您可能在 vi 模式下使用过的 :0read!:0r! 的简写(字面意思相同),但 : 在这里是可选的。
写入特殊行 #0 会自动将所有内容“向下”推送,然后您只需 :wq 即可保存您的更改。

$ head -n 5 "$source"
******  This goes on TOP  ******
TRUE(1)                                                    User Commands                                                    TRUE(1)

NAME
       true - do nothing, successfully

此外,一些较旧的 sed 实现似乎没有 ex 默认应具有的扩展(如 \U&)。