bash - Bash:使用另一个文件的行查找和替换文件中的行
问题描述
我有两个文件:masterlist.txt
一个有数百行 URL,另一个文件中需要替换toupdate.txt
的更新版本的行数较少。masterlist.txt
我希望能够使用 Bash 自动执行此过程,因为这些列表的创建和利用已经在 bash 脚本中进行。
URL 的服务器部分是变化的部分,因此我们可以使用唯一部分进行匹配:/whatever/whatever_user.xml
,但是如何在 中查找和替换这些行masterlist.txt
?即如何遍历每一行,toupdate.txt
并在它以 结尾时/f_SomeName/f_SomeName_user.xml
,找到以 结尾masterlist.txt
并用新行替换整行?
就这样https://123456url.domain.com/26/path/f_SomeName/f_SomeName_user.xml
变成https://new-123.domain.com/1/path/f_SomeName/f_SomeName_user.xml
了例子。
其余部分masterlist.txt
需要保持不变,因此我们必须只查找和替换具有相同行尾 (ID) 的不同服务器的行。
结构
masterlist.txt
看起来像这样:
https://123456url.domain.com/26/path/f_SomeName/f_SomeName_user.xml
https://456789url.domain.com/32/path/f_AnotherName/f_AnotherName_user.xml
https://101112url.domain.com/1/path/g_SomethingElse/g_SomethingElse_user.xml
https://222blah11.domain.com/19/path/e_BlahBlah/e_BlahBlah_user.xml
[...]
toupdate.txt
看起来像这样:
https://new-123.domain.com/1/path/f_SomeName/f_SomeName_user.xml
https://foo-254.domain.com/8/path/g_SomethingElse/g_SomethingElse_user.xml
期望的结果
masterlist.txt
看起来像:
https://new-123.domain.com/1/path/f_SomeName/f_SomeName_user.xml
https://456789url.domain.com/32/path/f_AnotherName/f_AnotherName_user.xml
https://foo-254.domain.com/8/path/g_SomethingElse/g_SomethingElse_user.xml
https://222blah11.domain.com/19/path/e_BlahBlah/e_BlahBlah_user.xml
[...]
初步检查
我看过sed
但我不知道如何使用两个文件中的行进行查找和替换?
到目前为止,这是我所拥有的,至少在进行文件处理:
#!/bin/bash
#...
while read -r line; do
# there's a new link on each line
link="${line}"
# extract the unique part from the end of each line
grabXML="${link##*/}"
grabID="${grabXML%_user.xml}"
# if we cannot grab the ID, then just set it to use the full link so we don't have an empty string
if [ -n "${grabID}" ]; then
identifier=${grabID}
else
identifier="${line}"
fi
## the find and replace here? ##
# we're done when we've reached the end of the file
done < "masterlist.txt"
解决方案
请您尝试以下方法:
#!/bin/bash
declare -A map
while IFS= read -r line; do
if [[ $line =~ (/[^/]+/[^/]*\.xml)$ ]]; then
uniq_part="${BASH_REMATCH[1]}"
map[$uniq_part]=$line
fi
done < "toupdate.txt"
while IFS= read -r line; do
if [[ $line =~ (/[^/]+/[^/]*\.xml)$ ]]; then
uniq_part="${BASH_REMATCH[1]}"
if [[ -n ${map[$uniq_part]} ]]; then
line=${map[$uniq_part]}
fi
fi
echo "$line"
done < "masterlist.txt" > "masterlist_tmp.txt"
# if the result of "masterlist_tmp.txt" is good enough, uncomment the line below
# mv -f -- "masterlist_tmp.txt" "masterlist.txt"
结果:
https://new-123.domain.com/1/path/f_SomeName/f_SomeName_user.xml
https://456789url.domain.com/32/path/f_AnotherName/f_AnotherName_user.xml
https://foo-254.domain.com/8/path/g_SomethingElse/g_SomethingElse_user.xml
https://222blah11.domain.com/19/path/e_BlahBlah/e_BlahBlah_user.xml
[说明]
- 关联数组
map
将“唯一部分”映射/f_SomeName/f_SomeName_user.xml
到“完整路径”,例如https://new-123.domain.com/1/path/f_SomeName/f_SomeName_user.xml
. (/[^/]+/[^/]*\.xml)$
如果匹配, 则 regex将 shell 变量分配给BASH_REMATCH[1]
从第二个最右边的斜杠到字符串末尾的扩展“.xml”的子字符串。- 在文件“toupdate.txt”的第一个循环中,它生成“唯一部分”和“填充路径”对作为关联数组的键值对。
- 在文件“masterlist.txt”的第二个循环中,测试提取的“唯一部分”是否存在关联值。如果是这样,则该行将替换为关联的值,即“toupdate.txt”文件中的行。
[替代]
如果文本文件很大,bash
可能不够快。在这种情况下,awk
脚本将更有效地工作:
awk 'NR==FNR {
if (match($0, "/[^/]+/[^/]*\\.xml$")) {
map[substr($0, RSTART, RLENGTH)] = $0
}
next
}
{
if (match($0, "/[^/]+/[^/]*\\.xml$")) {
full_path = map[substr($0, RSTART, RLENGTH)]
if (full_path != "") {
$0 = full_path
}
}
print
}' "toupdate.txt" "masterlist.txt" > "masterlist_tmp.txt"
[说明]
- 该
NR==FNR { BLOCK1; next } { BLOCK2 }
语法是为每个文件单独切换处理的常用习惯用法。由于NR==FNR
仅参数列表中的第一个文件满足条件并且next
语句跳过以下块,BLOCK1
因此仅处理文件“toupdate.txt”。同样BLOCK2
只处理文件“masterlist.txt”。 - 如果函数
match($0, pattern)
成功,它将awk
变量 设置为从文件中读取的当前记录RSTART
中匹配子字符串的起始位置,然后将变量设置为匹配子字符串的长度。现在我们可以 使用函数提取匹配的子字符串。$0
RLENGTH
/f_SomeName/f_SomeName_user.xml
substr()
- 然后我们分配数组
map
,以便子字符串(唯一部分)映射到“toupdate.txt”中的整个 url。 - 第二个块的工作方式与第一个块大部分相似。如果在数组中找到与键对应的值
map
,则将记录 ($0) 替换为该键索引的数组的值。
推荐阅读
- mongodb - 将 mongodb 连接到 minecraft 插件
- vue.js - 如何将 npm 模块导入 Vue.js 应用程序?
- python - 命令处理程序 Telethon
- python - 为什么我的 Python 程序中的时间没有更新?
- postgresql - 选择性转储/使用外键对 postgres 数据库进行采样
- javascript - MinMax 算法 Hex 游戏 Javascript
- c++ - 如何防止实例调用 C++ 中的构造函数?
- ios - UITableView - 如何检查部分页脚是否在屏幕上完全可见并相应滚动以使部分页脚完全可见?
- python - 在运行 celery 应用程序中更改并发/管理队列
- angular - Angular 库 - 找不到模块:错误:无法解析模块