Tüm “İkili Olmayan” dosyaları bulma


43

findBir dizindeki tüm "ikili olmayan" dosyaları bulmak için bu komutu kullanmak mümkün mü ? İşte çözmeye çalıştığım sorun.

Windows kullanıcısından bir dosya arşivi aldım. Bu arşiv kaynak kodunu ve resim dosyalarını içerir. Derleme sistemimiz, Windows satır sonlarına sahip dosyalar ile iyi oynamıyor. flip -uSatır sonlarını * nix ve pencereler arasında çevirecek bir komut satırı programım ( ) var. Yani, böyle bir şey yapmak istiyorum

find . -type f | xargs flip -u

Ancak, bu komut bir görüntü dosyasına veya başka bir ikili ortam dosyasına karşı çalıştırılırsa, dosyayı bozar. Dosya uzantılarının bir listesini yapabileceğimi ve bununla filtrelendirebileceğimin farkındayım, ancak bu listeyi güncel tutmak konusunda bana güvenmeyen bir şey istiyorum.

Peki, tüm ikili olmayan dosyaları bir dizin ağacında bulmanın bir yolu var mı? Yoksa göz önünde bulundurmam gereken alternatif bir çözüm var mı?


1
fileDosyanın veri mi yoksa metin mi olduğunu belirlemek için yardımcı programı komut dosyanızda / pipeline'ınızda bir yerde kullanabilirsiniz
lk-

1
İkili olmayanlar derken ne demek istiyorsunuz (modern bir bilgisayarda her şey ikilidir). Sanırım metin ve ikili dosyalara sahip eski C / PM işletim sisteminden farkı kullanıyorsunuz. Metin dosyaları herhangi bir uzunlukta olabilirdi, ancak bir ctrl-z ile bitmesi gerekiyordu ve ikili dosyalar 512 baytlık bir bloğun katı olmalıydı. Eğer öyleyse, anlamı metin dosyası. (İkili olmayan dosyalarda biten satır sonları hakkında yazdığınızı da unutmayın, bu aynı zamanda bunların metin dosyaları olduğunu da gösterir)
ctrl-alt-delor

Tüm dosyalar ikilidir, sadece bir yorumlama materyalidir. Metin dosyalarını nasıl bulacağınızı mı soruyorsunuz?
ctrl-alt-delor

@ richard Ben düz metin düz metin olarak yorumlanması gereken dosyaları ve diğer tüm dosyaları (görüntüler, kelime işlem belgeleri, vb.) ikili olarak adlandırdığımız dosyaları çağırdığımız bir çağ oluşturuyorum . Hepsinin sadece birinin ve başlığın altındaki sıfırlarının olduğunu biliyorum :)
Alan Storm

1
Ah, terimlerim hakkında ne demek istediğinizi anlıyorum - Gelecekte karışıklığı önlemek için ikili / metin kullanacağım. Re: \ r \ n şey - bu benim bir daktilo satırının (satırın başına gitme) ve satır besleme (bir satır aşağı gitme) ASCII karakterleri olduğunu anlıyorum. Demek ki, gerçek karakterin "daha doğru" bir modeli, çizgi karakterinin sonu içindi. OS X öncesi, Mac'ler bunun için sadece bir tane kullandı. Ben genellikle her şeyi "hala uğraştığımız acele yapılan seçimler" olarak yazarım
Alan Storm

Yanıtlar:


20

fileMetin dosyalarını bulmak için çıktıyı grep veya awk olarak kullanır ve kullanırdım , sonra fileçıktısının sadece dosya adı kısmını ve xargs'a dönüştürdüm.

gibi bir şey:

file * | awk -F: '/ASCII text/ {print $1}' | xargs -d'\n' -r flip -u

Grep'in yalnızca 'metin' yerine 'ASCII metni' aradığını unutmayın; muhtemelen Zengin Metin belgeleri veya unicode metin dosyaları vb. İle uğraşmak istemezsiniz.

findİncelenecek dosyaların bir listesini oluşturmak için de (ya da her neyse) kullanabilirsiniz file:

find /path/to/files -type f -exec file {} + | \
  awk -F: '/ASCII text/ {print $1}' | xargs -d'\n' -r flip -u

-d'\n'Xargs için bağımsız değişken Xargs böylece boşluklar ve diğer sorunlu karakterlerle dosya için yemek, ayrı bir bağımsız değişken olarak, her giriş hattını tedavi sağlar. yani bir alternatiftir xargs -0giriş kaynağı değildir ya da (örneğin, NULL ayrılmış çıkış oluşturmaz zaman findbireyin -print0opsiyon). Changelog'a göre, xargs Eylül 2005'te -d/ --delimiterseçeneğini aldı, bu yüzden herhangi bir antik olmayan linux dağıtımında olmalı (emin değildim, bu yüzden kontrol ettim - bu yüzden sadece "yeni" bir ek olduğunu hatırladım).

Bir satır beslemesinin dosya adlarında geçerli bir karakter olduğunu unutmayın, bu nedenle herhangi bir dosya adında satır beslemesi varsa bu durum bozulur. Tipik bir unix kullanıcısı için bu, patolojik olarak deliliktir, ancak dosyalar Mac veya Windows makinelerinde ortaya çıkmışsa duyulmamış değildir.

Ayrıca filemükemmel olmadığını unutmayın . Bir dosyadaki veri türünü tespit etmede çok iyidir, ancak zaman zaman karışabilir.

Geçmişte başarı ile defalarca bu yöntemin çok sayıda varyasyonlarını kullandım.


1
Bu çözüm için teşekkürler! Bazı sebeple fileekranlara English textziyade ASCII textbenim Solaris sistemde, ben buna göre o kısmını modifiye böylece. Ayrıca awk -F: '{print $1}'eşdeğeri ile değiştirdim cut -f1 -d:.
Andrew Cheong

3
Söylemeye değer grep -Ifiltreler ikili dosyalar
xenoterracide

Kelimeyi aramak textyeterli olmalı. Bu, veya veya filegibi açıklamaları da toplayacaktır . ASCII Java program textHTML document texttroff or preprocessor input text
user1024

Cevabım kısmen bu cevabın cevabı / iyileştirilmesi. RTF'leri ASCII textkarıştırmamak için grepping konusunda çok iyi bir nokta .
Joker

1
xenoterracide: Hayatımı kurtardın! Sadece bir bayrak -I ve BINGO
Sergio Abreu

9

Hayır. İkili veya ikili olmayan bir dosya için özel bir şey yoktur. 'Yalnızca 0x01–0x7F'deki karakterleri içeren' gibi sezgisel taramaları kullanabilirsiniz, ancak bu ASCII olmayan karakterli ikili dosyaları olan metin dosyalarını ve şanssız ikili dosyaları içeren metin dosyalarını arayacaktır.

Şimdi, bir kere bunu görmezden geldin ...

zip dosyaları

Windows kullanıcınızdan bir zip dosyası olarak geliyorsa, zip formatı, dosyaları arşivin içindeki ikili veya metin olarak işaretlemeyi destekler. Buna -adikkat etmek ve dönüştürmek için unzip'in seçeneğini kullanabilirsiniz . Elbette, bunun neden iyi bir fikir olamayacağına ilişkin ilk paragrafa bakınız (zip programı arşivlendiğinde yanlış tahmin etmiş olabilir).

zipinfo, hangi dosyaların zipfile listesinde ikili (b) veya text (t) olduğunu size söyleyecektir.

diğer dosyalar

File komutu bir dosyaya bakacak ve onu tanımlamaya çalışacaktır. Özellikle, muhtemelen -i(çıkış MIME tipi) seçeneğini faydalı bulacaksınız ; sadece text / * türündeki dosyaları dönüştür


6

Tek işlem dışı ikili dosyalarına genel bir çözüm bashkullanarak 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)

Dosya yardımcı programının yazarı ile iletişime geçtim ve -005.26 sürümünde (2016-04-16 yayımlandı, örneğin şimdiki Arch ve Ubuntu 16.10'da) file\0result\0, bir kerede beslenen birden fazla dosyayı basan bu şekilde yapabileceğiniz şık bir paramter ekledi. Örneğin:

find . -type f -exec file -00 --mime-encoding {} + |
  awk 'BEGIN{ORS=RS="\0"}{if(NR%2)f=$0;else if(!/binary/)print f}' | 

( awkBölüm, ikili olmayan her dosyayı filtrelemektir. ORSÇıktı ayracıdır.)

Tabii ki bir döngüde de kullanılabilir:

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}')

Bundan ve öncekinden yola çıkarak, daha yeni sürümlerdeki parametresini bashkullanarak yeni yöntemi kullanan ve eski sürümlerde önceki yönteme geri düşen ikili dosyaları filtrelemek için küçük bir komut dosyası oluşturdum :-00file

#!/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

Veya burada daha fazla POSIX-y olanı, ancak bunun için destek gerektirir 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

6

Kabul edilen cevap benim için hepsini bulamadı. İkilileri -Iyok saymak için grep's kullanmanın ve tüm gizli dosyaları görmezden gelmenin bir örneği ...

find . -type f -not -path '*/\.*' -exec grep -Il '.' {} \; | xargs -L 1 echo 

İşte pratik bir uygulamada kullanılıyor: dos2unix

https://unix.stackexchange.com/a/365679/112190


4

Cas'ın cevabı iyidir, ancak aklı başında dosya isimleri varsayar ; özellikle de dosya adlarının yeni satırlar içermeyeceği varsayılır.

Bu varsayımı burada yapmak için iyi bir neden yoktur, çünkü bu davayı doğru bir şekilde ele almak oldukça basit (ve bence daha temiz):

find . -type f -exec sh -c 'file "$1" | grep -q "ASCII text"' sh {} \; -exec flip -u {} \;

findKomut sadece kullanan POSIX belirtilen özelliklere . Kullanma -execBoole testleri gibi rasgele komutları çalıştırmak için basit ve sağlam (doğru kolları tek dosya) ve daha taşınabilir -print0.

Aslında, komutun tüm bölümleri hariç POSIX tarafından belirtilir flip.

Döndürdüğü filesonuçların doğruluğunu garanti etmediğini unutmayın . Bununla birlikte, pratikte çıktısında "ASCII metni" için grepping oldukça güvenilirdir.

(Belki bazı metin dosyalarını kaçırabilir , ancak bir ikili dosyayı yanlış bir şekilde "ASCII text" olarak tanımlamak ve dolaştırmak çok olası değildir, bu yüzden dikkatli olun.


Argümansız dosya callsoldukça yavaş olabilir, örneğin videolar için kodlama hakkında her şeyi size söyler.
phk

Ayrıca hiçbir dosyanın başlamayacağını varsayıyorsunuz -.
phk

Ve neden sadece tek bir çağrı yapmamanız için hiçbir neden göremiyorum file, bu argüman olarak birden fazla dosya alabilir.
phk

@ phk, yorumlarınızı ele almak için: (1) potansiyel yavaşlığı bilmek güzel, ama bunu engellemek için bir POSIX yolu göremiyorum; (2) Komut , kabuk komutuna iletilen herhangi bir dosya adının önüne geçeceği için dosya isimleri hakkında sıfır varsayım yapıyorum ; (3) Aynı anda tek bir komut çıktısında test olarak kullanmak , yeni satırlar içerebilecek dosya adlarının doğru kullanılmasını garanti etmeyi görebildiğim tek POSIX yoludur. find./grepfile
Wildcard

Son "POSIX-y" çözümünüzü inceledim ve bunun zekice olduğunu düşünüyorum - ancak bayrak ve ayırıcıyı filedesteklemediğini --mime-encodingve bunların --hiçbirinin POSIX tarafından garanti edilmediğini varsayıyorsunuz .
Wildcard

2
find . -type f -exec grep -I -q . {} \; -print

Bu -type f, mevcut dizinde (veya altında) grepboş ve ikili olmadığını düşünen tüm düzenli dosyaları ( ) bulacaktır .

Bu kullanır grep -Iikili ve ikili olmayan dosyaları ayırt etmek. -IBayrak ve neden olacaktır grepbir dosya ikili olduğunu tespit ettiğinde sıfır olmayan bir çıkış durumu ile çıkmak için. Bir "ikili" dosya, grepyazdırılabilir ASCII aralığının dışında karakter içeren bir dosyadır.

-qSeçeneği için grepverilen desen herhangi bir veri yaymadan, bulunursa o sıfır çıkış durumu ile çıkmak neden olacaktır. Kullandığımız desen, herhangi bir karakterle eşleşecek tek bir noktadır.

Dosyanın ikili olmadığı tespit edilirse ve en az bir karakter içeriyorsa, dosyanın adı yazdırılır.

Eğer cesur hissediyorsanız, kendinize de takabilirsiniz flip -u:

find . -type f -exec grep -I -q . {} \; -print -exec flip -u {} \;

1

Bunu dene :

find . -type f -print0 | xargs -0 -r grep -Z -L -U '[^         -~]' | xargs -0 -r flip -u

Nerede bir argüman grep '[^ -~]'DİR '[^<tab><space>-~]'.

Bir kabuk komut satırına yazarsanız, önce Ctrl+ yazın . Bir editörde problem olmamalı.VTab

  • '[^<tab><space>-~]'ASCII metni olmayan herhangi bir karakterle eşleşir (satırbaşları yoksayılır grep).
  • -L yalnızca eşleşmeyen dosyaların dosya adını yazdıracak
  • -Zboş bir karakterle ayrılmış dosya adlarını çıkarır (for xargs -0)

Perl benzeri Regex grep -P(varsa) \tile mevcut olduğunu belirtmekte fayda var . Alternatif olarak, eğer kabuk destekliyorsa yerel çeviri kullanmak: $'\t'( bashve zshyapar).
phk

1

Alternatif çözüm:

Dos2unix komutu, satır sonlarını Windows CRLF'den Unix LF'ye dönüştürür ve otomatik olarak ikili dosyaları atlar. Tekrarlayarak kullanarak uygularım:

find . -type f -exec dos2unix {} \;

Yana dos2unixargüman olarak birden dosya adlarını alabilir, bunu yapmak için çok daha verimli olduğunufind . -type f -exec dos2unix {} +
Anthon

0

sudo find / (-type f -ve -path '* / git / *' -iname 'README') -exec grep -liI '100644 \ | 100755' {} \; -exec çevirme -u {} \;

i. (-type f -ve -path '* / git / *' -iname 'README'): git adını ve README adını taşıyan dosyayı içeren bir yoldaki dosyaları arar. Belirli bir klasör ve dosya adını biliyorsanız, onu aramanız faydalı olacaktır.

ii.-exec komutu, find tarafından oluşturulan dosya adına bir komut çalıştırır.

iii. \; komutun sonunu belirtir

iv. {}, önceki arama aramasında bulunan dosya / katlayıcı adının çıktısıdır.

v.Çoklu komutlar daha sonra çalıştırılabilir. -Exec "command" \ ekleyerek; -exec flip -u \ gibi;

vii.grep

1.-l lists the name of the file
2.-I searches only non-binary files
3.-q quiet output
4.'100644\|100755' searches for either 100644 or 100755 within the file found. if found it then runs flip -u. \| is the or operator for grep. 

Bu test dizinini klonlayabilir ve deneyebilirsiniz: https://github.com/alphaCTzo7G/stackexchange/tree/master/linux/findSolution204092017

burada daha ayrıntılı cevap: https://github.com/alphaCTzo7G/stackexchange/blob/master/linux/findSolution204092017/README.md

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.