我有包含多列和“,”作为分隔符的 .csv 文件。网址位于第一列。我需要将所有网址转换为域而不删除其他列
我拥有的数据示例:
https://www.example.com/dog/url/path/cat.php,column2,$3,4
http://www.unix.random.com/index.html,column2,$3,4
http://example.com/dog/cat.php,column2,$3,4
www.example.com/dog/,column2,$3,4
example.com/url/path/cat/dog,column2,$3,4
https://example.com/,column2,$3,4
https://www.unix.random.com,column2,$3,4
http://www.example.com,column2,$3,4
http://example.com,column2,$3,4
www.random.com,column2,$3,4
example.com/,column2,$3,4
我需要将第 1 列中的所有 url 转换为域名而不触及其他列,其他列不包含“/”。我需要保留 www 之外的子域。
输出需要是:
example.com,column2,$3,4
unix.random.com,column2,$3,4
example.com,column2,$3,4
example.com,column2,$3,4
example.com,column2,$3,4
example.com,column2,$3,4
unix.random.com,column2,$3,4
example.com,column2,$3,4
example.com,column2,$3,4
random.com,column2,$3,4
example.com,column2,$3,4
这个怎么做?
答案1
使用任何 awk:
$ awk 'BEGIN{FS=OFS=","} {sub("^([^/:]+://)?(www[.])?","",$1); sub("/.*","",$1)} 1' file
example.com,column2,$3,4
unix.random.com,column2,$3,4
example.com,column2,$3,4
example.com,column2,$3,4
example.com,column2,$3,4
example.com,column2,$3,4
unix.random.com,column2,$3,4
example.com,column2,$3,4
example.com,column2,$3,4
random.com,column2,$3,4
example.com,column2,$3,4
答案2
我相信这有效:
sed -E 's#^(.*://)?(www\.)?##; s#^([^,/]+)[^,]*#\1#'
第一个 sed 命令 ( s#^(.*://)?(www\.)?##
) 与协议和“www”相匹配。并用任何东西替换它。第二个 sed 命令 ( s#^([^,/]+)[^,]*#\1#
) 匹配第一个斜杠之前的所有内容,然后匹配第一个逗号之前的所有内容,并将其替换为第一个斜杠之前的所有内容,因此它实际上删除了从第一个斜杠到第一个逗号之间的所有内容。
答案3
这可能不是您正在寻找的答案,但 sed 在不同操作系统之间可能不一致,并且其语法难以阅读。
这可能更糟,但另一种选择是在命令行上使用 Node.js 以及-e
评估字符串的标志。这样做的缺点是您必须在系统上安装 Node.js。
此代码获取从标准输入通过管道传输到它的所有内容,并将修改后的字符串打印到标准输出:
cat infile.csv | node -e 'const stdin = process.openStdin();
let data = "";
stdin.on("data", chunk => data += chunk);
stdin.on("end", () => {
console.log(
data
.trim()
.split("\n")
.filter(Boolean)
.map((line) => {
const parts = line.split(",");
const url = new URL((!/^http(s)?\:\/\//.test(line) ? "https://" : "") + parts.shift());
return `${url.host.replace(/^www\./,"")},${parts.join(",")}`
})
.join("\n"))
});' > outfile.csv
你可能有覆盖您的输入文件时遇到问题如果那是你想做的。为了解决这个问题,您可以在代码后面将文件名作为参数传递,而不是使用管道:
node -e 'const fs = require("fs");
const infile = process.argv[1]; const data = fs.readFileSync(infile).toString();
const output = data
.trim()
.split("\n")
.filter(Boolean)
.map((line) => {
const parts = line.split(",");
const url = new URL((!/^http(s)?\:\/\//.test(line) ? "https://" : "") + parts.shift());
return `${url.host.replace(/^www\./,"")},${parts.join(",")}`
})
.join("\n");
fs.writeFileSync(infile, output)' file.csv
答案4
使用乐(以前称为 Perl_6)
raku -pe 's{ (^ <-[/]>* \/\/ )? (w**3 \.)? (<-[/]>*) <-[,]>* } = "$2";'
[以上是@HatLess 代码的翻译sed
]。
raku -pe 's{ ^ (.* "://" )? (www\.)? } = ""; s{ ^ (<-[,/]>+) <-[,]>* } = "$0";'
sed
[以上是@D_Bear 代码的翻译]。
示例输出(两种情况):
example.com,column2,$3,4
unix.random.com,column2,$3,4
example.com,column2,$3,4
example.com,column2,$3,4
example.com,column2,$3,4
example.com,column2,$3,4
unix.random.com,column2,$3,4
example.com,column2,$3,4
example.com,column2,$3,4
random.com,column2,$3,4
example.com,column2,$3,4