そのようなファイルを特定できるLinuxコマンドラインコマンドとは何ですか?
find
コマンド(またはgrep
)はmatchテキストファイル内の特定の文字列のみを認識できます。しかし、コンテンツ全体を照合したいのです。つまり、どのファイルが正規表現\0+
に一致するかを確認したいのですが、行末の文字を無視してです。多分find . cat | grep
イディオムはうまくいくかもしれませんが、grepを無視して行を無視する方法(そしてファイルをバイナリとして扱う方法)がわかりません。
背景:数日おきにラップトップがフリーズすると、btrfsパーティションの情報が失われます。書き込み用に開かれたファイルの内容はゼロに置き換えられます(ファイルのサイズはほぼそのままです)。私は同期を使用しており、これらの偽のファイルを伝播させたくありません。バックアップから取得できるように、それらを識別する方法が必要です。
Perl正規表現モードを使用して、␀文字に対してgrep
を実行できます。
$ echo -ne "\0\0" > nul.bin
$ echo -ne "\0x\0" > non-nul.bin
$ grep -P "[^\0]" *.bin
Binary file non-nul.bin matches
だからあなたはこれを使うことができます:
for path in *.foo
do
grep -P "[^\0]" "$path" || echo "$path"
done
問題の根本を見つけることについてD_Byeが言っていることに同意します。
とにかく、ファイルに\0
または\n
のみが含まれているかどうかを確認するには、tr
を使用できます。
<file tr -d '\0\n' | wc -c
Null/newlineおよび空のファイルに対しては0を返します。
これらのファイルはスパースであると思われます。つまり、ファイルにディスクスペースが割り当てられておらず、ファイルサイズを指定しているだけです(du
は0を報告します)。
その場合、GNU findを使用すると、次のようにできます(ファイルパスに改行文字が含まれていないと仮定)。
find . -type f -size +0 -printf '%b:%p\n' | grep '^0:' | cut -d: -f2-
これができる小さなpythonプログラムです:
import sys
def only_contains_nulls(fobj, chunk_size=1024):
first = True
while True:
data = fobj.read(chunk_size)
if not data:
if first:
return 1 # No data
else:
return 0
if data.strip("\0"):
return 1
first = False
if __name__ == '__main__':
with open(sys.argv[1]) as f:
sys.exit(only_contains_nulls(f))
そして実際に:
$ printf '\0\0\0' > file
$ ./onlynulls file && echo "Only nulls" || echo "Non-null characters"
Only nulls
$ printf a >> file
$ ./onlynulls file && echo "Only nulls" || echo "Non-null characters"
Non-null characters
Findの-exec
、xargs
、GNU parallel
、および同様のプログラムを使用して、複数のファイルをチェックできます。または、必要なファイル名を出力します対処する:
files=( file1 file2 )
for file in "${files[@]}"; do
./onlynulls "$file" || printf '%s\n' "$file"
done
この出力を別のプログラムに渡す場合は、ファイル名に改行を含めることができるため、別の方法で区切る必要があります(\0
で適切に)。
多数のファイルがある場合は、一度に1つのファイルしか読み取らないため、並列処理のオプションを使用することをお勧めします。
このワンライナーは、GNU find
、xargs
、およびgrep
を使用して100%nulファイルを見つける最も効率的な方法です後者はPCREサポートで構築されています):
find . -type f -size +0 -readable -print0 |
LC_ALL=C xargs -r0 grep -LP "[^\x00]" --
他の提供された回答に対するこの方法の利点は次のとおりです。
Permission denied
警告は回避されます。grep
は、null以外のバイトを見つけた後、ファイルからのデータの読み取りを停止します(LC_ALL=C
は、各byteを確認するために使用されます) 文字)として解釈されます。grep
プロセスが少なくなります。-
で始まるパスは正しく処理されます。-Z
オプションをgrep
に渡し、xargs -r0 ...
を使用すると、100%nulファイルでさらにアクションを実行できます(例:クリーンアップ):
find . -type f -size +0 -readable -print0 |
LC_ALL=C xargs -0 grep -ZLP "[^\x00]" -- |
xargs -r0 rm --
また、find
オプション-P
を使用してシンボリックリンクの追跡を回避し、-xdev
を使用してファイルシステムのトラバースを回避することもお勧めします(リモートマウント、デバイスツリー、バインドマウントなど)。
行末文字を無視する場合の場合、次のバリアントが機能するはずです(これはそれほど良い考えではないと思います)。
find . -type f -size +0 -readable -print0 |
LC_ALL=C xargs -r0 grep -LP "[^\x00\r\n]" --
バックアップを防止するために不要なファイル(nul /改行文字100%)を削除することを含め、すべてをまとめます。
find -P . -xdev -type f -size +0 -readable -print0 |
LC_ALL=C xargs -0 grep -ZLP "[^\x00\r\n]" -- |
xargs -0 rm --
空のファイル(ゼロバイト)を含めることはお勧めしません。それらは veryspecificpurposes でしばしば存在します。
Null-chars '\ 0'と改行文字 '\ n'のみを含むファイルを検索します。
sedのq
を使用すると、行内でnull以外の文字が見つかると、各ファイル検索がすぐに終了します。
find -type f -name 'file-*' |
while IFS= read -r file ;do
out=$(sed -n '1=; /^\x00\+$/d; i non-null
; q' "$file")
[[ $out == "1" ]] && echo "$file"
done
テストファイルを作成する
> file-empty
printf '%s\n' 'line1' 'line2' 'line3' > file-with-text
printf '%4s\n' '' '' xx | sed 's/ /\x00/g' > file-with-text-and-nulls
printf '%4s\n' '' '' '' | sed 's/ /\x00/g' > file-with-nulls-and-newlines
printf '%4s' '' '' '' | sed 's/ /\x00/g' > file-with-nulls-only
出力
./file-with-nulls-and-newlines
./file-with-nulls-only
エイリアスを定義します。
alias is_binary="python -c 'import sys; sys.exit(not b\"\x00\" in open(sys.argv[1], \"rb\").read())'"
試して:
$ is_binary /etc/hosts; echo $?
1
$ is_binary `which which`; echo $?
0
すべてのバイナリファイルを再帰的に検索します。
IS_BINARY='import sys; sys.exit(not b"\x00" in open(sys.argv[1], "rb").read())'
find . -type f -exec bash -c "python -c '$IS_BINARY' {} && echo {}" \;
すべての非バイナリファイルを検索するには、&&
と||
。
GNU sedを使用する場合、-z
オプション。これは、行をゼロで終了する文字列として定義し、次のように空行を照合して削除します。
if [ "$( sed -z '/^$/d' "$file" | head -c 1 | wc -c )" -eq 0 ]; then
echo "$file contains only NULL!"
fi
その間のヘッドコマンドは、最適化にすぎません。