使用 bash 数组的 sed 查找替换失败
sed find replace using bash arrays fails
我有三个文件,两个文件,每个文件有2259个IP地址。一个文件包含 137772。该脚本使用带有 bash 数组的 sed 和一个 for 循环来将 access.log 中的 IP 替换为不同的 IP。 运行 几个小时后,脚本失败并出现此错误:
sed:-e 表达式 #1,字符 0:没有先前的正则表达式
uniq IP地址数量也少了6个IP
这是脚本:
#!/bin/bash
_ORGIFS=$IFS
IFS=$'\n'
_alIPs=($(<access.log.IPs)
_fIPs=($(<randomIPs.txt)
for (( _i=1; _i<=2259; _i++ ))
do
sed -i "s/${_alIPs[$_i]}/${_fIPs[$_i]}/g" access.log
done
IFS=$_ORGIFS
这取自我自己的bash模板库,按需使用:
# parse a template and return it
# 1st arg is template tags [array]
# 2nd arg is replacement values for template tags [array]
# 3rd arg is template file path
# usage: TT=$(parseTemplate TAGS[@] REPLACE[@] $MAIL_TEMPLATE); echo $TT;
function parseTemplate()
{
local _TAG=("${!1}")
local _REPLACE=("${!2}")
local _TEMPLATE=""
local _PATTERN=""
local i
if [[ ${#_TAG[@]} > 0 ]]; then
_PATTERN="-e s#\%\%${_TAG[0]}\%\%#${_REPLACE[0]}#g"
for (( i = 1 ; i < ${#_TAG[@]} ; i++ ))
do
_PATTERN="${_PATTERN}; s#\%\%${_TAG[${i}]}\%\%#${_REPLACE[${i}]}#g"
done
local SED=`which sed`
$SED "${_PATTERN}" < "${_TEMPLATE}"
else
local CAT=`which cat`
$CAT "${_TEMPLATE}"
fi
}
模板替换标签具有这种格式:%%TAG%%
可以更改它,但这是此函数使用的格式
示例模板(文件或文本):
Hello %%NAME%%, your location is %%LOCATION%%
TAGS = ('NAME' 'LOCATION');
REPLACE = ('Nikos' 'GR')
TT=$(parseTemplate TAGS[@] REPLACE[@] $MAIL_TEMPLATE);
echo $TT;
bash 中的数组索引从 0 开始。当你说
for (( _i=1; _i<=2259; _i++ ))
您忽略了第一个条目并在末尾进行了一次,此时
sed -i "s/${_alIPs[$_i]}/${_fIPs[$_i]}/g" access.log
扩展到
sed -i "s//something/g" access.log
s
命令中的 //
试图重用之前使用的正则表达式,该正则表达式不存在,因此出现错误。
解决方法是使用
for (( _i=0; _i<2259; _i++ ))
...尽管说真的,我会花一些时间思考如何批量进行这些替换。
附录:如
sed -i -f <(paste access.log.IPs randomIPs.txt | awk '{ print "s/" "/" "/g" }') access.log
(假设我没看错你的意图)
我有三个文件,两个文件,每个文件有2259个IP地址。一个文件包含 137772。该脚本使用带有 bash 数组的 sed 和一个 for 循环来将 access.log 中的 IP 替换为不同的 IP。 运行 几个小时后,脚本失败并出现此错误:
sed:-e 表达式 #1,字符 0:没有先前的正则表达式
uniq IP地址数量也少了6个IP
这是脚本:
#!/bin/bash
_ORGIFS=$IFS
IFS=$'\n'
_alIPs=($(<access.log.IPs)
_fIPs=($(<randomIPs.txt)
for (( _i=1; _i<=2259; _i++ ))
do
sed -i "s/${_alIPs[$_i]}/${_fIPs[$_i]}/g" access.log
done
IFS=$_ORGIFS
这取自我自己的bash模板库,按需使用:
# parse a template and return it
# 1st arg is template tags [array]
# 2nd arg is replacement values for template tags [array]
# 3rd arg is template file path
# usage: TT=$(parseTemplate TAGS[@] REPLACE[@] $MAIL_TEMPLATE); echo $TT;
function parseTemplate()
{
local _TAG=("${!1}")
local _REPLACE=("${!2}")
local _TEMPLATE=""
local _PATTERN=""
local i
if [[ ${#_TAG[@]} > 0 ]]; then
_PATTERN="-e s#\%\%${_TAG[0]}\%\%#${_REPLACE[0]}#g"
for (( i = 1 ; i < ${#_TAG[@]} ; i++ ))
do
_PATTERN="${_PATTERN}; s#\%\%${_TAG[${i}]}\%\%#${_REPLACE[${i}]}#g"
done
local SED=`which sed`
$SED "${_PATTERN}" < "${_TEMPLATE}"
else
local CAT=`which cat`
$CAT "${_TEMPLATE}"
fi
}
模板替换标签具有这种格式:%%TAG%%
可以更改它,但这是此函数使用的格式
示例模板(文件或文本):
Hello %%NAME%%, your location is %%LOCATION%%
TAGS = ('NAME' 'LOCATION');
REPLACE = ('Nikos' 'GR')
TT=$(parseTemplate TAGS[@] REPLACE[@] $MAIL_TEMPLATE);
echo $TT;
bash 中的数组索引从 0 开始。当你说
for (( _i=1; _i<=2259; _i++ ))
您忽略了第一个条目并在末尾进行了一次,此时
sed -i "s/${_alIPs[$_i]}/${_fIPs[$_i]}/g" access.log
扩展到
sed -i "s//something/g" access.log
s
命令中的 //
试图重用之前使用的正则表达式,该正则表达式不存在,因此出现错误。
解决方法是使用
for (( _i=0; _i<2259; _i++ ))
...尽管说真的,我会花一些时间思考如何批量进行这些替换。
附录:如
sed -i -f <(paste access.log.IPs randomIPs.txt | awk '{ print "s/" "/" "/g" }') access.log
(假设我没看错你的意图)