使用 sed 更改特定行中的特定字符
Using sed in order to change a specific character in a specific line
我是 bash 的初学者,这是我的问题。我有一个这样的文件:
Azzzezzzezzzezzz...
Bzzzezzzezzzezzz...
Czzzezzzezzzezzz...
我尝试在脚本中编辑此文件。ABC
字母在所有文件中都是唯一的,每行只有一个字母。
我想用一个数字替换每行的第一个 e
可以是 :
1
以 A
, 开头的行
2
以 B
, 开头的行
3
以 C
, 开头的行
我想循环这个以获得这种类型的结果
Azzz1zzz5zzz1zzz...
Bzzz2zzz4zzz5zzz...
Czzz3zzz6zzz3zzz...
这里的所有数字都是 0 到 9 之间的随机 int 变量。我真的需要首先在我的循环的第一个执行中替换 1,2,3,然后是 5,4,6,然后是 1,5,3 和等等。
我试过了
sed "0,/e/s/e//;0,/e/s/e//;0,/e/s/e//" /tmp/myfile
但是结果是这样的(因为我没有指定行)
Azzz1zzz2zzz3zzz...
Bzzzezzzezzzezzz...
Czzzezzzezzzezzz...
我注意到 sed -i "/A/ s/$/ezzz/" /tmp/myfile
会在 A 行的末尾添加 ezzz
所以我尝试了这个
sed -i "/A/ 0,/e/s/e//;/B/ 0,/e/s/e//;/C/ 0,/e/s/e//" /tmp/myfile
但是失败了
sed: -e expression #1, char 5: unknown command: `0'
我迷路了。
我在一个变量(我们称之为 number_of_e_per_line
)中有 A
、B
或 C
行中 e
的数量。
感谢您抽出宝贵的时间。
只需在匹配 A
.
的行上应用 s
命令
sed '
/^A/{ s/e//; }
/^B/{ s/e//; }
# or shorter
/^C/s/e//
'
s
命令默认替换第一个匹配项。例如,您可以执行 s/s//2
替换第二个出现,s/e//g
(如“全局”)替换所有出现。
0,/e/
指定 行的范围 - 它从第一行开始过滤行,直到匹配 /e/
.
的行
sed
不是 Bash 的一部分。它是一种独立的(原始的)编程语言,是一个非常标准的命令。参见 https://www.grymoire.com/Unix/Sed.html。
从评论继续。 sed
在这里是一个糟糕的选择,除非你所有的文件只能有 3 行。原因是 sed
处理每一行,无法单独计算 'e'
.
的出现次数
相反,将 sed
包装在脚本中并跟踪替换内容可以让您处理任何文件,无论行数如何。您只需循环并一次处理一行,例如
#!/bin/bash
[ -z "" ] && { ## valiate one argument for filename provided
printf "error: filename argument required.\nusage: %s filename\n" "./" >&2
exit 1
}
[ -s "" ] || { ## validate file exists and non-empty
printf "error: file not found or empty '%s'.\n" ""
exit 1
}
declare -i n=1 ## occurrence counter initialized 1
## loop reading each line
while read -r line || [ -n "$line" ]; do
[[ $line =~ ^.*e.*$ ]] || continue ## line has 'e' or get next
sed "s/e/1/$n" <<< "$line" ## substitute the 'n' occurence of 'e'
((n++)) ## increment counter
done < ""
您的数据文件每行末尾有 "..."
表明您的文件比发布的代码段大。如果您有以 'A' - 'Z'
开头的行,您不想写 26 个单独的 /match/s/find/replace/
替换。如果你有 3 到 26(或更多)之间的某个地方,你不想为你面对的每个新文件重写不同的 sed
表达式。
这就是为什么我说 sed
是一个糟糕的选择。你真的没有办法用 sed
使任务成为通用任务。使用脚本的缺点是它会成为一个糟糕的选择,因为您需要处理的记录数量会增加(超过 100000 条左右只是由于效率)
例子Use/Output
使用 replace-e-incremental.sh
中的脚本和 file
中的数据,您可以:
$ bash replace-e-incremental.sh file
Azzz1zzzezzzezzz...
Bzzzezzz1zzzezzz...
Czzzezzzezzz1zzz...
修改file
In-Place
由于你在这里多次调用sed
,你需要将文件的输出重定向到一个临时文件,然后用临时文件覆盖它来替换原来的文件,例如
$ bash replace-e-incremental.sh file > mytempfile && mv -f mytempfile file
$ cat file
Azzz1zzzezzzezzz...
Bzzzezzz1zzzezzz...
Czzzezzzezzz1zzz...
我是 bash 的初学者,这是我的问题。我有一个这样的文件:
Azzzezzzezzzezzz...
Bzzzezzzezzzezzz...
Czzzezzzezzzezzz...
我尝试在脚本中编辑此文件。ABC
字母在所有文件中都是唯一的,每行只有一个字母。
我想用一个数字替换每行的第一个 e
可以是 :
1
以A
, 开头的行
2
以B
, 开头的行
3
以C
, 开头的行
我想循环这个以获得这种类型的结果
Azzz1zzz5zzz1zzz...
Bzzz2zzz4zzz5zzz...
Czzz3zzz6zzz3zzz...
这里的所有数字都是 0 到 9 之间的随机 int 变量。我真的需要首先在我的循环的第一个执行中替换 1,2,3,然后是 5,4,6,然后是 1,5,3 和等等。
我试过了
sed "0,/e/s/e//;0,/e/s/e//;0,/e/s/e//" /tmp/myfile
但是结果是这样的(因为我没有指定行)
Azzz1zzz2zzz3zzz...
Bzzzezzzezzzezzz...
Czzzezzzezzzezzz...
我注意到 sed -i "/A/ s/$/ezzz/" /tmp/myfile
会在 A 行的末尾添加 ezzz
所以我尝试了这个
sed -i "/A/ 0,/e/s/e//;/B/ 0,/e/s/e//;/C/ 0,/e/s/e//" /tmp/myfile
但是失败了
sed: -e expression #1, char 5: unknown command: `0'
我迷路了。
我在一个变量(我们称之为 number_of_e_per_line
)中有 A
、B
或 C
行中 e
的数量。
感谢您抽出宝贵的时间。
只需在匹配 A
.
s
命令
sed '
/^A/{ s/e//; }
/^B/{ s/e//; }
# or shorter
/^C/s/e//
'
s
命令默认替换第一个匹配项。例如,您可以执行 s/s//2
替换第二个出现,s/e//g
(如“全局”)替换所有出现。
0,/e/
指定 行的范围 - 它从第一行开始过滤行,直到匹配 /e/
.
sed
不是 Bash 的一部分。它是一种独立的(原始的)编程语言,是一个非常标准的命令。参见 https://www.grymoire.com/Unix/Sed.html。
从评论继续。 sed
在这里是一个糟糕的选择,除非你所有的文件只能有 3 行。原因是 sed
处理每一行,无法单独计算 'e'
.
相反,将 sed
包装在脚本中并跟踪替换内容可以让您处理任何文件,无论行数如何。您只需循环并一次处理一行,例如
#!/bin/bash
[ -z "" ] && { ## valiate one argument for filename provided
printf "error: filename argument required.\nusage: %s filename\n" "./" >&2
exit 1
}
[ -s "" ] || { ## validate file exists and non-empty
printf "error: file not found or empty '%s'.\n" ""
exit 1
}
declare -i n=1 ## occurrence counter initialized 1
## loop reading each line
while read -r line || [ -n "$line" ]; do
[[ $line =~ ^.*e.*$ ]] || continue ## line has 'e' or get next
sed "s/e/1/$n" <<< "$line" ## substitute the 'n' occurence of 'e'
((n++)) ## increment counter
done < ""
您的数据文件每行末尾有 "..."
表明您的文件比发布的代码段大。如果您有以 'A' - 'Z'
开头的行,您不想写 26 个单独的 /match/s/find/replace/
替换。如果你有 3 到 26(或更多)之间的某个地方,你不想为你面对的每个新文件重写不同的 sed
表达式。
这就是为什么我说 sed
是一个糟糕的选择。你真的没有办法用 sed
使任务成为通用任务。使用脚本的缺点是它会成为一个糟糕的选择,因为您需要处理的记录数量会增加(超过 100000 条左右只是由于效率)
例子Use/Output
使用 replace-e-incremental.sh
中的脚本和 file
中的数据,您可以:
$ bash replace-e-incremental.sh file
Azzz1zzzezzzezzz...
Bzzzezzz1zzzezzz...
Czzzezzzezzz1zzz...
修改file
In-Place
由于你在这里多次调用sed
,你需要将文件的输出重定向到一个临时文件,然后用临时文件覆盖它来替换原来的文件,例如
$ bash replace-e-incremental.sh file > mytempfile && mv -f mytempfile file
$ cat file
Azzz1zzzezzzezzz...
Bzzzezzz1zzzezzz...
Czzzezzzezzz1zzz...