Bash - 用第二个数组中的字符串替换第一个数组中的文件字符串
Bash - replace in file strings from first array with strings from second array
我有两个数组。第一个填充了 grep
从我想用下载的新文件替换的文件中编辑的值。
请注意,我不确切知道第一个数组的样子,这意味着某些值将具有 _,其他值为 - 有些人不会有任何这些,并在名称后立即放置 :(冒号)。
示例数组:
array1:
[account:123 shoppingcart-1:123 notification-core_1:123 notification-dispatcher_core_1:123 notification-dispatcher-smschannel_core_1:123]
array2:
[account_custom_2:124 shoppingcart_custom_2:124 notification_custom_2:124 notification-dispatcher_custom_2:124 notification-dispatcher-smschannel_custom_2:124]
这些数组是唯一的例子,有超过 50 个值要替换。
我正在对第二个数组中的每个项目与第一个数组中的每个项目进行比较,如下所示:
file_name="<path_to_file>/file.txt"
for i in "${!array1[@]}"
do
for j in "${!array2[@]}"
do
array_2_base="`echo ${array2[$j]} | awk -F_ '{print }'`"
if [[ "${array1[$i]}" == *"$array_2_base"* ]]
then
sed -i "s=${array1[$i]}=${array2[$j]}=g" $file_name
fi
done
done
这里我只对第二个数组中的每个项目的第一部分进行子字符串化,这样我就可以将它与第一个数组中的项目进行比较。
例如account_custom_2:124 -> 账户 或 notification-dispatcher_custom_2:124 -> 通知调度程序。
这很好用,但是当 notification 在 notification-core_1:123[= 时我遇到了问题53=] 和 notification-dispatcher_core_1:123 和 notification-dispatcher-smschannel_core_1:123.
能否请您就如何解决此问题提出建议,或者是否可以建议另一种方法?
我找到了解决这个问题的方法。
替换后我将从第一个数组中删除字符串。
file_name="<path_to_file>/file.txt"
for i in "${!array1[@]}"
do
for j in "${!array2[@]}"
do
array_2_base="`echo ${array2[$j]} | awk -F_ '{print }'`"
if [[ "${array1[$i]}" == *"$array_2_base"* ]]
then
sed -i "s=${array1[$i]}=${array2[$j]}=g" $file_name
delete="${array1[$i]}"
array1=( "${array1[@]/$delete}" )
fi
done
done
如果数组中的项数相等,则可以在一个循环中处理它们
for i in "${!array1[@]}"; {
value=${array1[$i]}
new_value=${array2[$i]}
sed -i "s/$value/$new_value/" file
}
重点是array2元素的base
可能包含其他元素
作为子字符串,将根据顺序导致不正确的替换
的匹配。
为避免这种情况,您可以 sort
降序排列数组,以便
较长的图案在前。
假设数组中的字符串不包含制表符,将
你请试试:
file_name="<path_to_file>/file.txt"
array1=(account:123 shoppingcart-1:123 notification-core_1:123 notification-dispatcher_core_1:123 notification-dispatcher-smschannel_core_1:123)
array2=(account_custom_2:124 shoppingcart_custom_2:124 notification_custom_2:124 notification-dispatcher_custom_2:124 notification-dispatcher-smschannel_custom_2:124)
# insert the following block to sort array2 in descending order
array2=( $(for j in "${array2[@]}"; do
array_2_base=${j%%_*}
printf "%s\t%s\n" "$array_2_base" "$j"
done | sort -r | cut -f2-) )
# the following code will work "as is"
for i in "${!array1[@]}"
do
for j in "${!array2[@]}"
do
array_2_base="`echo ${array2[$j]} | awk -F_ '{print }'`"
if [[ "${array1[$i]}" == *"$array_2_base"* ]]
then
sed -i "s=${array1[$i]}=${array2[$j]}=g" "$file_name"
delete="${array1[$i]}"
array1=( "${array1[@]/$delete}" )
fi
done
done
由于重复,上面的脚本在执行时间上会很低效
调用 sed -i
命令。
下面的脚本会 运行 更快
通过预先生成 sed
脚本并只执行一次。
file_name="<path_to_file>/file.txt"
array1=(
account:123
shoppingcart-1:123
notification-core_1:123
notification-dispatcher_core_1:123
notification-dispatcher-smschannel_core_1:123
)
array2=(
account_custom_2:124
shoppingcart_custom_2:124
notification_custom_2:124
notification-dispatcher_custom_2:124
notification-dispatcher-smschannel_custom_2:124
)
while IFS=$'\t' read -r base a2; do # read the sorted list line by line
for a1 in "${array1[@]}"; do
if [[ $a1 == *$base* ]]; then
scr+="s=$a1=$a2=g;" # generate sed script by appending the "s" command
continue 2
fi
done
done < <(for j in "${array2[@]}"; do
array_2_base=${j%%_*} # substring before the 1st "_"
printf "%s\t%s\n" "$array_2_base" "$j"
# print base and original element side by side
done | sort -r)
sed -i "$scr" "$file_name" # execute the replacement at once
我有两个数组。第一个填充了 grep
从我想用下载的新文件替换的文件中编辑的值。
请注意,我不确切知道第一个数组的样子,这意味着某些值将具有 _,其他值为 - 有些人不会有任何这些,并在名称后立即放置 :(冒号)。
示例数组:
array1:
[account:123 shoppingcart-1:123 notification-core_1:123 notification-dispatcher_core_1:123 notification-dispatcher-smschannel_core_1:123]
array2:
[account_custom_2:124 shoppingcart_custom_2:124 notification_custom_2:124 notification-dispatcher_custom_2:124 notification-dispatcher-smschannel_custom_2:124]
这些数组是唯一的例子,有超过 50 个值要替换。
我正在对第二个数组中的每个项目与第一个数组中的每个项目进行比较,如下所示:
file_name="<path_to_file>/file.txt"
for i in "${!array1[@]}"
do
for j in "${!array2[@]}"
do
array_2_base="`echo ${array2[$j]} | awk -F_ '{print }'`"
if [[ "${array1[$i]}" == *"$array_2_base"* ]]
then
sed -i "s=${array1[$i]}=${array2[$j]}=g" $file_name
fi
done
done
这里我只对第二个数组中的每个项目的第一部分进行子字符串化,这样我就可以将它与第一个数组中的项目进行比较。
例如account_custom_2:124 -> 账户 或 notification-dispatcher_custom_2:124 -> 通知调度程序。
这很好用,但是当 notification 在 notification-core_1:123[= 时我遇到了问题53=] 和 notification-dispatcher_core_1:123 和 notification-dispatcher-smschannel_core_1:123.
能否请您就如何解决此问题提出建议,或者是否可以建议另一种方法?
我找到了解决这个问题的方法。
替换后我将从第一个数组中删除字符串。
file_name="<path_to_file>/file.txt"
for i in "${!array1[@]}"
do
for j in "${!array2[@]}"
do
array_2_base="`echo ${array2[$j]} | awk -F_ '{print }'`"
if [[ "${array1[$i]}" == *"$array_2_base"* ]]
then
sed -i "s=${array1[$i]}=${array2[$j]}=g" $file_name
delete="${array1[$i]}"
array1=( "${array1[@]/$delete}" )
fi
done
done
如果数组中的项数相等,则可以在一个循环中处理它们
for i in "${!array1[@]}"; {
value=${array1[$i]}
new_value=${array2[$i]}
sed -i "s/$value/$new_value/" file
}
重点是array2元素的base
可能包含其他元素
作为子字符串,将根据顺序导致不正确的替换
的匹配。
为避免这种情况,您可以 sort
降序排列数组,以便
较长的图案在前。
假设数组中的字符串不包含制表符,将 你请试试:
file_name="<path_to_file>/file.txt"
array1=(account:123 shoppingcart-1:123 notification-core_1:123 notification-dispatcher_core_1:123 notification-dispatcher-smschannel_core_1:123)
array2=(account_custom_2:124 shoppingcart_custom_2:124 notification_custom_2:124 notification-dispatcher_custom_2:124 notification-dispatcher-smschannel_custom_2:124)
# insert the following block to sort array2 in descending order
array2=( $(for j in "${array2[@]}"; do
array_2_base=${j%%_*}
printf "%s\t%s\n" "$array_2_base" "$j"
done | sort -r | cut -f2-) )
# the following code will work "as is"
for i in "${!array1[@]}"
do
for j in "${!array2[@]}"
do
array_2_base="`echo ${array2[$j]} | awk -F_ '{print }'`"
if [[ "${array1[$i]}" == *"$array_2_base"* ]]
then
sed -i "s=${array1[$i]}=${array2[$j]}=g" "$file_name"
delete="${array1[$i]}"
array1=( "${array1[@]/$delete}" )
fi
done
done
由于重复,上面的脚本在执行时间上会很低效
调用 sed -i
命令。
下面的脚本会 运行 更快
通过预先生成 sed
脚本并只执行一次。
file_name="<path_to_file>/file.txt"
array1=(
account:123
shoppingcart-1:123
notification-core_1:123
notification-dispatcher_core_1:123
notification-dispatcher-smschannel_core_1:123
)
array2=(
account_custom_2:124
shoppingcart_custom_2:124
notification_custom_2:124
notification-dispatcher_custom_2:124
notification-dispatcher-smschannel_custom_2:124
)
while IFS=$'\t' read -r base a2; do # read the sorted list line by line
for a1 in "${array1[@]}"; do
if [[ $a1 == *$base* ]]; then
scr+="s=$a1=$a2=g;" # generate sed script by appending the "s" command
continue 2
fi
done
done < <(for j in "${array2[@]}"; do
array_2_base=${j%%_*} # substring before the 1st "_"
printf "%s\t%s\n" "$array_2_base" "$j"
# print base and original element side by side
done | sort -r)
sed -i "$scr" "$file_name" # execute the replacement at once