回復したいtarファイルがあります。問題は、tar
のstderrがそれと混在していて、stdout
ファイルが次のようになることです:
% head android-1435613730.tar
tar: removing leading '/' from member names
factory/0000775000175100017510000000000007033241671011512 5ustar radioradiofactory/
factory/lost+found/0000700000000000000000000000000000000000000013242 5ustar rootrootfactory/lost+found/
tar: /factory/lost+found: Permission denied
factory/wifi/0000770000175000017510000000000007033241625012667 5ustar systemradiofactory/wifi/
tar: /factory/wifi: Permission denied
factory/imei/0000775000175100017510000000000007033241600012425 5ustar radioradiofactory/imei/
tar: can't open '/factory/nv_data.bin': Permission denied
tar: can't open '/factory/nv_data.bin.md5': Permission denied
factory/bluetooth/0000755000175100017510000000000007033241674013520 5ustar radioradiofactory/bluetooth/
次のエラーメッセージを削除してみました。
% grep --color=never -v --binary-file=text '^tar:.*$' android-1435613730.tar | tar -tv
drwxrwxr-x radio/radio 0 1999-12-31 16:00 factory/
tar: Skipping to next header
drwx------ install/all_a124 0 2015-06-29 13:51 acct/uid/50124/
tar: Skipping to next header
tar: Exiting with failure status due to previous errors
ただし、ご覧のとおり、これによりエラーが発生します。 (私はひどいバイナリデータファイルダンプを提供しません。本物必要。 )
また、このファイルはかなり大きく(6.7GB)、利用可能なコアやスワップがそれほど多くないことを指摘する必要があります。
tar
このターボールは、それを生成するために使用されたGNU Tar 1.27.1を使用して解凍されています。
@kosの提案に従ってPerlを使ってみました。
% <android-1435613730.tar perl -pe 's/\n?tar: [^\n]*\n//sg' | tar -tv
drwxrwxr-x radio/radio 0 1999-12-31 16:00 factory/
tar: Skipping to next header
drwx------ install/all_a83 0 2015-06-29 13:55 acct/uid/50083/
tar: Skipping to next header
tar: Exiting with failure status due to previous errors
あなたの便宜のために問題を再現するスクリプトは次のとおりです。
#!/bin/sh
TMPDIR=$(mktemp -d)
cd $TMPDIR
for i in test test2 test3; do
mkdir $i
echo $i > $i/$i
done
chmod 000 test2/test2
chmod 000 test3
tar -c test* > broken.tar 2>&1
echo "Created corrupt tarball in $TMPDIR"
私のタルボールには途中でエラーが混在していますが、ここでは再現できないようです。
答え1
stdout
合計が行バッファリングされ、両方の行が常に検索可能である場合、混合は問題になりません。合計が行バッファリングされ、行を簡単に検索できるstderr
プログラムの出力を考えてみましょう。stdout
stderr
stderr
$ cat file
xxxxxxxxxx
tar: ----------
yyyyyyyyyy
tar: ----------
zzzzzzzzzz
tar: ----------
以下を使用してどちらかを抽出することはgrep
問題ではありません。
$ < file grep -v ^tar
xxxxxxxxxx # stdout line 1
yyyyyyyyyy # stdout line 2
zzzzzzzzzz # stdout line 3
$ < file grep ^tar
tar: ---------- # stderr line 1
tar: ---------- # stderr line 2
tar: ---------- # stderr line 3
stdout
ただし、ある時点でバッファリング動作がバッファリングなしに変更された場合を考えてください。
x
tar: ----------
xxxxxxxxxyyy
tar: ----------
yyyyyyyzzzzz
tar: ----------
zzzzz
抽出stdout
と使用grep
はい1つの質問:
$ < file grep -v ^tar
x # wrong stdout line 1
xxxxxxxxxyyy # wrong stdout line 2
yyyyyyyzzzzz # wrong stdout line 3
zzzzz # wrong stdout line 4
この試み:
< file perl -0777pe 's/\n?tar: [^\n]*\n//g' > newfile
[一番上]場合を除き、元のstdout
コンテンツはファイルから抽出する必要があります。
$ < file perl -0777pe 's/\n?tar: [^\n]*\n//g'
xxxxxxxxxxyyyyyyyyyyzzzzzzzzzz