我有.tsv
一个文件,其中包含 s3 存储桶的源和目标信息。我正在使用 while 循环从该文件读取源路径和目标路径并执行s3 cp
操作。请注意,该文件包含 100K 行。
如何使用sed
命令使文件中的所有源路径和目标路径都变成双引号 ( xx.tsv
)。我需要双引号,因为 aws s3 无法处理其中包含空格的文件/文件夹名称,而不用""
.
我正在寻找类似以下 3 行的内容将被更改
s3://data01/repo01/image live01.png s3://Ata01/vol01/image live01.png
s3://data02/repo01/image live01.png s3://Ata02/vol01/image live01.png
s3://data03/repo01/image live01.png s3://Ata03/vol01/image live01.png
到
"s3://data01/repo01/image live01.png" "s3://Ata01/vol01/image live01.png"
"s3://data02/repo01/image live01.png" "s3://Ata02/vol01/image live01.png"
"s3://data03/repo01/image live01.png" "s3://Ata03/vol01/image live01.png"
答案1
在每个 Unix 机器上的任何 shell 中使用任何 awk:
$ awk -F'\t' -v OFS='"\t"' '{print "\"" $1, $2 "\""}' file
"s3://data01/repo01/image live01.png" "s3://Ata01/vol01/image live01.png"
"s3://data02/repo01/image live01.png" "s3://Ata02/vol01/image live01.png"
"s3://data03/repo01/image live01.png" "s3://Ata03/vol01/image live01.png"
上面假设您的文件名都不包含制表符、换行符或双引号。
答案2
$ cat input.tsv
s3://data01/repo01/image live01.png s3://Ata01/vol01/image live01.png
s3://data02/repo01/image live01.png s3://Ata02/vol01/image live01.png
s3://data03/repo01/image live01.png s3://Ata03/vol01/image live01.png
注意:列之间用制表符分隔,而不是多个空格。
和sed
:
$ sed -E 's/^(s3:.*)\t+(s3:.*)/"\1"\t"\2"/' input.tsv
"s3://data01/repo01/image live01.png" "s3://Ata01/vol01/image live01.png"
"s3://data02/repo01/image live01.png" "s3://Ata02/vol01/image live01.png"
"s3://data03/repo01/image live01.png" "s3://Ata03/vol01/image live01.png"
在两个捕获组之间使用\s+
或代替也可以,并产生相同的输出。即[[:blank:]]+
\t
sed -E 's/^(s3:.*)[[:blank:]]+(s3:.*)/"\1"\t"\2"/' input.tsv
和
sed -E 's/^(s3:.*)\s+(s3:.*)/"\1"\t"\2"/' input.tsv
版本[[:blank:]]+
将匹配一个或多个空格或制表符作为列分隔符,而版本\s+
将匹配一个或多个任何空白字符(包括空格、制表符等)。
和awk
:
$ awk -F'\t' '{print "\"" $1 "\"\t\"" $2 "\""}' input.tsv
"s3://data01/repo01/image live01.png" "s3://Ata01/vol01/image live01.png"
"s3://data02/repo01/image live01.png" "s3://Ata02/vol01/image live01.png"
"s3://data03/repo01/image live01.png" "s3://Ata03/vol01/image live01.png"
答案3
将数据视为使用制表符作为字段分隔符的 CSV 文件:
csvformat -tT -U1 file.tsv >newfile.tsv
这使用csvformat
来自csvkit读取制表符分隔的输入 ( -t
) 并生成制表符分隔的输出 ( ) ,无论 CSV 格式是否需要,该输出都会被-T
引用 ( )。-U1
将文件视为 CSV 文件并使用 CSV 解析器为您进行引用的好处是,如果字段已被引用,则不会重复引用字段。
$ cat file.tsv
"s3://data01/repo01/image live01.png" s3://Ata01/vol01/image live01.png
s3://data02/repo01/image live01.png s3://Ata02/vol01/image live01.png
s3://data03/repo01/image live01.png s3://Ata03/vol01/image live01.png
$ csvformat -tT -U1 file.tsv
"s3://data01/repo01/image live01.png" "s3://Ata01/vol01/image live01.png"
"s3://data02/repo01/image live01.png" "s3://Ata02/vol01/image live01.png"
"s3://data03/repo01/image live01.png" "s3://Ata03/vol01/image live01.png"
显然,您也可以直接读取数据,并在调用时添加双引号s3 cp
。我不知道该命令是什么样的,但是......
while IFS=$'\t' read -r src dst; do
s3 cp "\"$src\"" "\"$dst\""
done <file.tsv
答案4
剥土豆皮的方法有很多,但我的是
sed 's;^\(s3://.*\) \(s3://.*\)$;"\1" "\2";' filename_in.tsv > out.tsv
它用于sed
在输入上应用正则表达式,捕获字符串中所有“不是 s3-URL 之间的空格”部分,然后将它们放入引号中。
我希望任何编写生成 .tsv 的工具的人都能从中学到一些东西 - 例如,如果文件名中存在换行符,这也可能会出现不可挽回的错误,这对于文件名来说是完全合法的(可能不在 S3 上,没查过)。
将文件名存储在“无论什么分隔符”的文件中都会以糟糕的方式结束(除非该分隔符是 0 字节,这几乎是文件名中唯一禁止的字节)。您需要转义,或者更好的是,不要在文本文件中存储长的文件名列表,而是使用简单的 SQLite 来使用。