bash シェルで sed/awk を使用して .tsv ファイル内の s3 バケット パスに二重引用符を追加する方法

bash シェルで sed/awk を使用して .tsv ファイル内の s3 バケット パスに二重引用符を追加する方法

.tsvS3 バケットのソースと宛先の情報を含むファイルがあります。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 ボックス上のあらゆるシェルで 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+2つのキャプチャグループ間でまたはを使用する[[: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:]]+は、列区切り文字として1つ以上のスペースまたはタブ文字と一致しますが、\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はから使用しますcsvキットタブ区切りの入力 ( ) を読み取り、 CSV 形式で要求されるかどうかに関係なく引用符( ) で囲まれた-tタブ区切りの出力 ( ) を生成します。-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 のように簡単に使用できるものを使用してください。

関連情報