Twitterでそんな感じの処理について書かれてたので、備忘で残しておく。 内容としては、tarで展開した後にファイルだけ頭に特定の文字列を追加するという内容。

GNU tarであればtransformオプションがあるから楽…ではあるのだが、Mac OSだとデフォルトではGNU tarは入ってないし、特定の条件下でないとうまく動作しない。

1. GNU tarの場合(特定の条件でのみ動作)

先程も書いたのだけど、GNU tarであれば --transform オプションというのがあり、これを使うことでsedのような形式で置換処理を書くことができる。

tar xzvf ./file.tar.gz --show-transformed-names --transform 's/foo/bar/g'
[REMOTE][blacknon@BS-PUB-UBUNTU-01][/tmp]
(`・ω・´) < tar tvf test_d.tar.gz
drwxrwxr-x blacknon/blacknon 0 2019-03-12 22:13 test_d/
-rw-rw-r-- blacknon/blacknon 0 2018-07-01 22:42 test_d/test0003.jpg
-rw-rw-r-- blacknon/blacknon 0 2018-07-01 22:42 test_d/test0002.jpg
-rw-rw-r-- blacknon/blacknon 0 2018-07-01 22:42 test_d/test0005.jpg
-rw-rw-r-- blacknon/blacknon 0 2018-07-01 22:42 test_d/test0001.jpg
-rw-rw-r-- blacknon/blacknon 0 2018-07-01 22:42 test_d/test0004.jpg
drwxrwxr-x blacknon/blacknon 0 2019-03-12 22:13 test_d/test_d2/
-rw-rw-r-- blacknon/blacknon 0 2018-07-01 22:42 test_d/test_d2/test0008.jpg
-rw-rw-r-- blacknon/blacknon 0 2018-07-01 22:42 test_d/test_d2/test0007.jpg
-rw-rw-r-- blacknon/blacknon 0 2018-07-01 22:42 test_d/test_d2/test0009.jpg
-rw-rw-r-- blacknon/blacknon 0 2018-07-01 22:42 test_d/test_d2/test0006.jpg
-rw-rw-r-- blacknon/blacknon 0 2018-07-01 22:42 test_d/test_d2/test0010.jpg

[REMOTE][blacknon@BS-PUB-UBUNTU-01][/tmp]
(`・ω・´) < tar xzvf test_d.tar.gz --show-transformed-names --transform 's/test/TEST/g'
TEST_d/
TEST_d/TEST0003.jpg
TEST_d/TEST0002.jpg
TEST_d/TEST0005.jpg
TEST_d/TEST0001.jpg
TEST_d/TEST0004.jpg
TEST_d/TEST_d2/
TEST_d/TEST_d2/TEST0008.jpg
TEST_d/TEST_d2/TEST0007.jpg
TEST_d/TEST_d2/TEST0009.jpg
TEST_d/TEST_d2/TEST0006.jpg
TEST_d/TEST_d2/TEST0010.jpg

なので、これを正規表現を使ってファイル名の頭に文字列が追加されるように書いてやればいい。

tar xzvf ./file.tar.gz --show-transformed-names --transform 's:.*/:&hoge_:'
[REMOTE][blacknon@BS-PUB-UBUNTU-01][/tmp]
(`・ω・´) < tar xzvf test_d.tar.gz --show-transformed-names --transform 's:.*/:&ABC_:'
test_d/
test_d/ABC_test0003.jpg
test_d/ABC_test0002.jpg
test_d/ABC_test0005.jpg
test_d/ABC_test0001.jpg
test_d/ABC_test0004.jpg
test_d/ABC_test_d2/
test_d/test_d2/ABC_test0008.jpg
test_d/test_d2/ABC_test0007.jpg
test_d/test_d2/ABC_test0009.jpg
test_d/test_d2/ABC_test0006.jpg
test_d/test_d2/ABC_test0010.jpg

ただ、実はこれだとちょっと失敗で、余計なディレクトリ(上の例だとABC_test_d2)が生成されてしまうことになる。 tarのtransformではsedのように条件指定ができないので、こういったディレクトリが作られてしまうことになる。

また、置換条件に .*/ を利用しているので、ディレクトリでアーカイブされていないファイルを展開する場合にもうまく動かないだろう。 なので、特定の条件にあるファイルであればこれで動作するが、そうでない場合は次に記述する方法を取るといいだろう。

2. -vオプションの出力を利用してmvする

tar単体ではうまくファイル名だけを置換するのが難しかったり、そもそもGNU tarが無かったりといったことがある。 じゃどうするというと、tarではvで展開する内容を出力できるので、それを利用してmvコマンドを生成し、そのままbashに食わせることで対応ができる。

MacOSとLinuxだとGNUコマンドの有無で動作が違うので、別々に記述する。

2.1. Linuxの場合

tar xzvf ./test_d.tar.gz | sed -r 's/.+/mv & \$(test -f & \&\& echo &|sed -r "\/.\/s:\(.*\/\):\\1ABC_:")/' | bash

2.2. MacOSの場合

tar xzvf ./test_d.tar.gz 2>&1 | \sed -E 's/^x //g' | \sed -E 's/.+/mv & \$(test -f & \&\& echo &|sed -E "\/.\/s:\(.*\/\):\\1ABC_:")/g' | bash
[REMOTE][blacknon@BS-PUB-UBUNTU-01][/tmp]
(`・ω・´) < tar xzvf ./test_d.tar.gz | sed -r 's/.+/mv & \$(test -f & \&\& echo &|sed -r "\/.\/s:\(.*\/\):\\1ABC_:")/' | bash
mv: 'test_d/' の後に宛先のファイルオペランドがありません
Try 'mv --help' for more information.
mv: 'test_d/test_d2/' の後に宛先のファイルオペランドがありません
Try 'mv --help' for more information.

[REMOTE][blacknon@BS-PUB-UBUNTU-01][/tmp]
(`・ω・´) < find ./test_d
./test_d
./test_d/ABC_test0003.jpg
./test_d/ABC_test0005.jpg
./test_d/ABC_test0001.jpg
./test_d/ABC_test0002.jpg
./test_d/ABC_test0004.jpg
./test_d/test_d2
./test_d/test_d2/ABC_test0006.jpg
./test_d/test_d2/ABC_test0007.jpg
./test_d/test_d2/ABC_test0008.jpg
./test_d/test_d2/ABC_test0009.jpg
./test_d/test_d2/ABC_test0010.jpg

面倒くさかったのでディレクトリ時のエラーは消してないが、必要であれば/dev/nullにでも出しておけばいいだろう。 fちゃちゃっと処理をすることを目標にしているのでディレクトリ名にスペースが入ってる場合等は考慮していないので、その場合は環境に合わせて書き加えたりするといいだろう。