我有.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+
or也可以工作,並產生相同的輸出。 IE[[: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 來使用。