find
このコマンドを使用して、ディレクトリ内の「バイナリではない」ファイルをすべて見つけることができますか?これが私が解決したい問題です。
Windowsユーザーからファイルアーカイブを受け取りました。アーカイブにはソースコードとイメージファイルが含まれています。私たちのビルドシステムは、Windows行の終わりを持つファイルをうまく処理しません。flip -u
* nixとwindowsの間に行末を反転するコマンドラインプログラム()があります。だから私はこのようなことをしたい。
find . -type f | xargs flip -u
ただし、イメージファイルまたは他のバイナリメディアファイルに対してこのコマンドを実行すると、ファイルが破損します。私はファイル拡張子のリストを作成し、それを使ってフィルタリングできることを知っていますが、そのリストを最新の状態に保つことに頼らない機能をしたいと思います。
もしそうなら、ディレクトリツリーでバイナリ以外のすべてのファイルを見つける方法はありますか?それとも別のソリューションを検討する必要がありますか?
答え1
出力を使用しfile
、grepまたはawkにパイプしてテキストファイルを見つけ、出力file
のファイル名部分のみを抽出してxargsにパイプします。
それは次のとおりです。
file * | awk -F: '/ASCII text/ {print $1}' | xargs -d'\n' -r flip -u
grep は「テキスト」ではなく「ASCII テキスト」を検索します。リッチテキスト文書やUnicodeテキストファイルなどを混乱させたくありません。
find
以下を使用するか、別の方法で確認するファイルのリストを作成することもできますfile
。
find /path/to/files -type f -exec file {} + | \
awk -F: '/ASCII text/ {print $1}' | xargs -d'\n' -r flip -u
xargsの引数は、-d'\n'
xargsが各入力行を別々の引数として処理し、スペースやその他の問題のある文字を含むファイル名を処理するようにします。つまり、xargs -0
入力ソースが NULL で区切られた出力 (たとえば、find
のオプション) を生成しないか、または生成できない-print0
場合の代替です。変更ログによると、xargsは2005年9月に-d
/オプションを取得した--delimiter
ので、古代以外のすべてのLinuxディストリビューションに存在する必要があります(わからないので確認しました。これが「最近の」追加項目であることを曖昧に覚えています)。
改行はファイル名の有効な文字なので、ファイル名に改行が含まれていると中断されます。一般的なUNIXユーザーにとって、これは病理学的に狂ったことですが、ファイルがMacまたはWindowsコンピュータに由来する場合は聞いたことがないことはありません。
また、これはfile
完璧ではないことに注意してください。ファイルのデータ型を検出するのは非常に効果的ですが、時には混乱します。
私は過去にこの方法のバリエーションを何度もうまく使用してきました。
答え2
find . -type f -exec grep -I -q . {} \; -print
-type f
これは、現在のディレクトリ(またはその下)で空ではgrep
なくバイナリではないと見なされるすべての一般的なファイル()を探します。
grep -I
バイナリファイルと非バイナリファイルを区別するために使用されます。このフラグは、ファイルがバイナリであると検出された場合、ゼロ以外の終了状態で終了するように-I
します。grep
によると、grep
「バイナリ」ファイルは、印刷可能なASCII範囲外の文字を含むファイルです。
指定されたパターンが見つかった場合、この-q
オプションを使用すると、データをエクスポートせずに終了ステータス0で終了します。grep
私たちが使用するパターンはドットであり、すべての文字と一致します。
ファイルがバイナリではなく、少なくとも 1 つの文字を含むことが確認された場合は、ファイル名を印刷します。
勇気がある場合は、flip -u
ここにコードを挿入することもできます。
find . -type f -exec grep -I -q . {} \; -print -exec flip -u {} \;
答え3
許可された回答が私に必要な回答をすべて見つけられませんでした。以下は、-I
grepを使用してバイナリファイルを無視し、すべての隠しファイルを無視する例です。
find . -type f -not -path '*/\.*' -exec grep -Il '.' {} \; | xargs -L 1 echo
これは実際のアプリケーションで使用されます:dos2unix
答え4
bash
以下を使用してバイナリ以外のファイルを処理するための一般的な解決策file -b --mime-encoding
:
while IFS= read -d '' -r file; do
[[ "$(file -b --mime-encoding "$file")" = binary ]] &&
{ echo "Skipping $file."; continue; }
echo "Processing $file."
# ...
done < <(find . -type f -print0)
作家に連絡しました。文書ユーティリティを使用して、彼は一度に複数のファイルを印刷できる-00
素晴らしいパラメータをバージョン5.26(2016-04-16リリース、現在のArchおよびUbuntu 16.10のように)に追加しました。file\0result\0
したがって、次のことができます。
find . -type f -exec file -00 --mime-encoding {} + |
awk 'BEGIN{ORS=RS="\0"}{if(NR%2)f=$0;else if(!/binary/)print f}' | …
(このawk
部分はバイナリではなくすべてのファイルをフィルタリングする部分です。ORS
は出力区切り文字です。)
もちろんループでも使用できます。
while IFS= read -d '' -r file; do
echo "Processing $file."
# ...
done < <(find . -type f -exec file -00 --mime-encoding {} + |
awk 'BEGIN{ORS=RS="\0"}{if(NR%2)f=$0;else if(!/binary/)print f}')
これと以前のバージョンに基づいて、最新bash
バージョンではパラメータとともに新しいメソッドを使用し-00
、file
以前のバージョンでは以前のメソッドに置き換えるバイナリフィルタリング用の小さなスクリプトを作成しました。
#!/bin/bash
# Expects files as arguments and returns the ones that do
# not appear to be binary files as a zero-separated list.
#
# USAGE:
# filter_binary_files.sh [FILES...]
#
# EXAMPLE:
# find . -type f -mtime +5 -exec ./filter_binary_files.sh {} + | xargs -0 ...
#
[[ $# -eq 0 ]] && exit
if [[ "$(file -v)" =~ file-([1-9][0-9]|[6-9]|5\.([3-9][0-9]|2[6-9])) ]]; then
file -00 --mime-encoding -- "$@" |
awk 'BEGIN{ORS=RS="\0"}{if(NR%2)f=$0;else if(!/binary/)print f}'
else
for f do
[[ "$(file -b --mime-encoding -- "$f")" != binary ]] &&
printf '%s\0' "$f"
done
fi
またはここにPOSIXに似ていますが、サポートが必要ですsort -V
。
#!/bin/sh
# Expects files as arguments and returns the ones that do
# not appear to be binary files as a zero-separated list.
#
# USAGE:
# filter_binary_files.sh [FILES...]
#
# EXAMPLE:
# find . -type f -mtime +5 -exec ./filter_binary_files.sh {} + | xargs -0 ...
#
[ $# -eq 0 ] && exit
if [ "$(printf '%s\n' 'file-5.26' "$(file -v | head -1)" | sort -V)" = \
'file-5.26' ]; then
file -00 --mime-encoding -- "$@" |
awk 'BEGIN{ORS=RS="\0"}{if(NR%2)f=$0;else if(!/binary/)print f}'
else
for f do
[ "$(file -b --mime-encoding -- "$f")" != binary ] &&
printf '%s\0' "$f"
done
fi