在每行开头添加前缀字符串

457

我有一个如下的文件:

line1
line2
line3

我想要得到:

prefixline1
prefixline2
prefixline3

我本来可以写一个 Ruby 脚本,但最好不需要。

prefix 将包含 /。它是一个路径,例如:/opt/workdir/

18个回答

700
# If you want to edit the file in-place
sed -i -e 's/^/prefix/' file

# If you want to create a new file
sed -e 's/^/prefix/' file > file.new
如果prefix包含/,你可以使用除prefix以外的任意字符,或者转义/,这样sed命令就变成了:
's#^#/opt/workdir#'
# or
's/^/\/opt\/workdir/'

6
不要忘记你也可以在管道中使用 sed,例如 foo | sed -e 's/^/x /' | bar - zigg
1
@Dataman 很酷。另一种方法是 sed -e '2,$s/^/prefix/' - Alok Singhal
10
如果您想在每行末尾添加字符串,请使用sed -e 's/$/postfix/' file - Brian
1
你为什么使用-e选项?您能解释一下为什么不在末尾加上g吗? - mf94
1
@alper 这可能应该是一个单独的问题,但以下内容对我有效:sed '/^prefix/!s/^/prefix/g' file - Alok Singhal
显示剩余16条评论

155
awk '$0="prefix"$0' file > new_file

在awk中,默认操作是'{print $0}'(即打印整行),因此上述代码等同于:

awk '{print "prefix"$0}' file > new_file
使用Perl(原地替换):

使用Perl可以进行原地替换:

perl -pi 's/^/prefix/' file

9
使用管道/流或变量:printf "$VARIABLE\n" | awk '$0="前缀"$0' - ThorSummoner
5
使用一个大文件(12 G),awk 报告 awk: out of memory in readrec 1 source line number 1,但是使用 sed 的解决方案成功完成。 - jrm
1
这是最好的答案,使用AWK可以直接运行,而不必烦恼地处理转义正则表达式特殊字符。 - Maximo Migliari
使用“普通文件”分割成行后,awk 不会耗尽内存... - rogerdpack

34

你可以在Ex模式下使用Vim:

ex -sc '%s/^/prefix/|x' file
  1. % 选择所有行

  2. s 替换

  3. x 保存并关闭


1
对我来说,我只需在vim中打开文件并键入“:%s/^/prefix/”,因为这种策略在许多情况下都非常有用。 - Frank Bryce

29
如果您的前缀比较复杂,只需将其放入变量中即可:
prefix=path/to/file/

然后,您传递该变量并让awk处理它:

awk -v prefix="$prefix" '{print prefix $0}' input_file.txt

17

使用moreutils中的ts命令,这里提供了一种非常易读的单行解决方案。

$ cat file | ts prefix | tr -d ' '

以及它是如何逐步推导出来的:

# Step 0. create the file

$ cat file
line1
line2
line3
# Step 1. add prefix to the beginning of each line

$ cat file | ts prefix
prefix line1
prefix line2
prefix line3
# Step 2. remove spaces in the middle

$ cat file | ts prefix | tr -d ' '
prefixline1
prefixline2
prefixline3

4
许多Linux发行版默认没有安装'ts'。此外,对这个答案进行投票反对是不恰当的,因为在答案中添加的"tr -d ' '"命令将从每行中删除所有空格,而不仅仅是由'ts'添加的那个空格。 - Tim Bird

13
如果您有Perl:
perl -pe 's/^/PREFIX/' input.file

8
使用 &(匹配模式的整个输入部分):
cat in.txt | sed -e "s/.*/prefix&/" > out.txt

或者使用回溯引用:

cat in.txt | sed -e "s/\(.*\)/prefix\1/" > out.txt

6

使用Shell:

#!/bin/bash
prefix="something"
file="file"
while read -r line
do
 echo "${prefix}$line"
done <$file > newfile
mv newfile $file

5

虽然我不认为pierr有这个问题,但我需要一种解决方案,不会延迟文件的实时“tail”输出,因为我想同时监视多个警报日志,并给每行加上其各自日志名称的前缀。

不幸的是,使用sed、cut等命令会引入太多缓冲,使我无法看到最新的行。Steven Penny建议使用nl-s选项,这很有意思,经过测试证明它没有引入我关心的不必要的缓冲。

然而,使用nl存在几个问题,涉及到去除不需要的行号(即使您不关心美观性,使用额外列可能是不可取的情况)。首先,使用“cut”剥离数字会重新引入缓冲问题,从而破坏解决方案。第二,“-w1”也没有帮助,因为这并不能限制行号只在一列中 - 它只会随着需要更多数字而变宽。

如果您想在其他地方捕捉它,这并不美观,但由于这正是我不需要做的事情(所有内容已经写入日志文件,我只是想实时同时查看多个日志),丢失行号并只留下我的前缀的最佳方法是在-s字符串中以回车符(CR或^M或Ctrl-M)开头。例如:

#!/bin/ksh

# Monitor the widget, framas, and dweezil
# log files until the operator hits <enter>
# to end monitoring.

PGRP=$$

for LOGFILE in widget framas dweezil
do
(
    tail -f $LOGFILE 2>&1 |
    nl -s"^M${LOGFILE}>  "
) &
sleep 1
done

read KILLEM

kill -- -${PGRP}

3
使用 -u 选项可以避免 sed 的缓冲。 - Bryan Larsen
2
可以使用unbuffer/stdbuf关闭缓冲,参见http://unix.stackexchange.com/q/25372/6205。 - myroslav

4

使用 ed:

ed infile <<'EOE'
,s/^/prefix/
wq
EOE

这个命令将每一行的开头(^)替换成prefix。使用wq保存并退出。

如果替换字符串中包含斜杠,我们可以使用不同的分隔符来代替s

ed infile <<'EOE'
,s#^#/opt/workdir/#
wq
EOE

我引用了here-doc的分界符EOE(“end of ed”)来防止参数扩展。在这个例子中,如果不加引号也可以工作,但是为了防止在ed脚本中有$时出现意外情况,这样做是一个好习惯。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接