如何在 bash shell 中使用 sed/awk 在 .tsv 檔案中為 s3 儲存桶路徑新增雙引號

如何在 bash shell 中使用 sed/awk 在 .tsv 檔案中為 s3 儲存桶路徑新增雙引號

我有.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 來使用。

相關內容