简体   繁体   English

如何使用 sed 或其他命令将现有字符串替换为每行不同的字符串

[英]How to use sed or other commands to replace existing string with a different string for each line

for i in 1 2 3 4 5 6 7; do
 sed "s/\number\b/& =$i/" print.txt 
done

print.txt contains: print.txt 包含:

number elephant
number giraffe
number dogs
number cats
number mouse
number pigs
number snake

How do I replace a word/string in ONE line of a text file in a for loop without changing every line?如何在不更改每一行的情况下在 for 循环中替换文本文件的一行中的单词/字符串? Whenever I run my script it makes all the 'number' into one specific number and by the time the last iteration runs, all the 'number' is replaced by 7. I understand why it does that, just not sure how to fix it.每当我运行我的脚本时,它都会将所有的“数字”变成一个特定的数字,到最后一次迭代运行时,所有的“数字”都被 7 替换。我明白为什么会这样,只是不知道如何解决它。

In this simple example, I want it to be outputted like this:在这个简单的例子中,我希望它像这样输出:

1 elephant
2 giraffe
3 dogs
4 cats
5 mouse
6 pigs
7 snake

But let's say, in my for loop, it defines a variable to be goat and the second iteration to be chicken, I want pigs to be changed to goat and snake to be changed to chicken, how do I do that inside my for loop?但是让我们说,在我的 for 循环中,它定义了一个变量为山羊,第二次迭代为鸡,我希望将猪更改为山羊,将蛇更改为鸡,我如何在 for 循环中执行此操作?

If I understand you want to replace "number" in each line with increasing values 1-7 , then you don't need (or want) a loop at all.如果我知道您想用递增的值1-7替换每一行中的"number" ,那么您根本不需要(或想要)循环。 Simply pipe the result of sed removing the "number" string from the beginning of each line to nl -w1 -s' ' to number the lines.只需将sed从每行开头删除"number"字符串的结果通过管道传输到nl -w1 -s' '以对行进行编号。 Example:例子:

$ sed 's/^number\s*//' print.txt | nl -w1 -s' '
1 elephant
2 giraffe
3 dogs
4 cats
5 mouse
6 pigs
7 snake

( note: you can use grep -o '\\w*$' print.txt | nl -w1 -s' ' as well) 注意:您也可以使用grep -o '\\w*$' print.txt | nl -w1 -s' '

You can adjust the number format and separator with options.您可以使用选项调整数字格式和分隔符。 See man 1 nl .参见man 1 nl

Why don't you want a loop?你为什么不想要一个循环? How many times are you invoking sed and spawning an additional subshell within your loop?你有多少次调用sed并在你的循环中产生一个额外的子shell? (one per-iteration). (每次迭代一次)。 This is horribly inefficient.这是非常低效的。 Any time you are looping in shell, you want to minimize the number of subshells spawned within your loop.任何时候在 shell 中循环时,您都希望尽量减少循环中产生的子 shell 的数量。

Can you do it with a loop as you were attempting?您可以在尝试时使用循环来完成吗? Of course, but it is one of the least efficient solutions you could come up with.当然,但它是您能想到的效率最低的解决方案之一。 To make it work in a loop, you have to limit your operation per-iteration to the wanted line in the file.要使其在循环中工作,您必须将每次迭代的操作限制为文件中所需的行。 You can do that by suppressing normal output and only outputting the line you changed, eg您可以通过抑制正常输出并仅输出您更改的行来做到这一点,例如

for i in 1 2 3 4 5 6 7; do
    sed -n "${i}s/number/$i/p" print.txt
done

( but DON'T do it this way... ) 但不要这样做......

If you want an even more efficient solution that eliminates the pipe and additional subshell, just use awk and a counter ( n below), eg如果你想要一个更有效的解决方案来消除管道和额外的子外壳,只需使用awk和一个计数器(下面的n ),例如

$ awk -v n=1 '{print n++ " " $2}' print.txt
1 elephant
2 giraffe
3 dogs
4 cats
5 mouse
6 pigs
7 snake

You can likewise further control the number and separator format using printf instead of print above.您同样可以使用printf而不是上面的print进一步控制数字和分隔符格式。

Let me know if you have questions or if you are wanting something different.如果您有问题或想要不同的东西,请告诉我。


Answer to Comment Question回答评论问题

If you have 3 lines with an identical field you want to change to something else, you first have to know what you want to change the identical fields to.如果您想将 3 行具有相同字段的内容更改为其他内容,则首先必须知道要将相同字段更改为什么。 That means you must have a replacement table or lookup table of replacements somewhere.这意味着您必须在某处有一个替换表替换查找表

Say your text file is actually:假设您的文本文件实际上是:

$ cat print2.txt
number elephant
number giraffe
number dogs
number cats
number pigs
number pigs
number pigs

And you want to change lines 5, 6, 7 from "pigs" to "goat", "cow", "chicken" in that order, then with awk you can read the replacement values into an array and make the replacements using a counter to determine which replacement to use.并且您想将第 5、6、7 行从"pigs"更改为"goat", "cow", "chicken" ,然后使用awk您可以将替换值读入数组并使用计数器进行替换以确定要使用的替代品。 (below we just fill an array with the three replacements) (下面我们只是用三个替换填充一个数组)

You can do something similar to the following:您可以执行类似以下操作:

awk 'BEGIN {n=1; rep[1]="goat"; rep[2]="cow"; rep[3]="chicken"}
    $2=="pigs"{$2=rep[n++]}
    {print}
' print2.txt

Copy/pasting at the command line would yield:在命令行复制/粘贴将产生:

$ awk 'BEGIN {n=1; rep[1]="goat"; rep[2]="cow"; rep[3]="chicken"}
>     $2=="pigs"{$2=rep[n++]}
>     {print}
> ' print2.txt
number elephant
number giraffe
number dogs
number cats
number goat
number cow
number chicken

So you can do what you ask in the comment -- you just need to know what you will replace repeats by in advance.所以你可以做你在评论中提出的要求——你只需要提前知道你将用什么来替换重复。

A pure bash shell solution without any external tools/utility.没有任何外部工具/实用程序的纯 bash shell 解决方案。

!/bin/bash

n=1
while read -r line; do
  printf '%s\n' "${line//number/"$n"}"
  ((n++))
done < print.txt

Using POSIX sh.使用 POSIX sh。

#!/bin/sh

n=1
while read -r line; do
  printf '%d. %s\n' "$n" "${line#* }"
  n=$((n+1))
done < print.txt

For a small size/set of data/input it should be fine.对于小尺寸/数据集/输入,它应该没问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM