Menemukan semua file "Non-Biner"


43

Apakah mungkin menggunakan findperintah untuk menemukan semua file "non-biner" dalam direktori? Inilah masalah yang saya coba selesaikan.

Saya telah menerima arsip file dari pengguna windows. Arsip ini berisi kode sumber dan file gambar. Sistem build kami tidak cocok dengan file yang memiliki ujung baris windows. Saya memiliki program command line ( flip -u) yang akan membalik akhir baris antara * nix dan windows. Jadi, saya ingin melakukan sesuatu seperti ini

find . -type f | xargs flip -u

Namun, jika perintah ini dijalankan terhadap file gambar, atau file media biner lainnya, itu akan merusak file. Saya menyadari bahwa saya dapat membuat daftar ekstensi file dan memfilternya, tetapi saya lebih suka memiliki sesuatu yang tidak bergantung pada saya untuk menjaga agar daftar itu tetap mutakhir.

Jadi, apakah ada cara untuk menemukan semua file non-biner di pohon direktori? Atau adakah solusi alternatif yang harus saya pertimbangkan?


1
Anda dapat menggunakan fileutilitas di suatu tempat di skrip / pipa Anda untuk mengidentifikasi apakah file tersebut adalah data atau teks
lk-

1
Apa yang Anda maksud dengan non-biner (semua yang ada di komputer modern adalah biner). Saya kira Anda menggunakan perbedaan dari sistem operasi C / PM lama, yang memiliki teks dan file biner. File teks bisa panjang tetapi harus diakhiri dengan ctrl-z, dan file biner harus merupakan kelipatan dari blok 512byte. Jika demikian, Anda berarti file teks. (Saya juga mencatat bahwa Anda menulis tentang akhiran file non-biner, ini juga menyarankan bahwa mereka adalah file teks) Apakah ini benar?
ctrl-alt-delor

Semua file adalah biner, itu hanya bahan interpretasi. Apakah Anda menanyakan cara menemukan file teks?
ctrl-alt-delor

@richard Saya datang dari era di mana kita memanggil file yang dimaksudkan untuk ditafsirkan sebagai teks biasa , dan semua file lainnya (gambar, dokumen pengolah kata, dll.) biner. Saya tahu ini semua hanya satu dan nol di bawah tenda :)
Alan Storm

1
Ah, saya mengerti maksud Anda tentang istilah saya - saya akan menggunakan biner / teks di masa depan untuk menghindari kebingungan. Re: the hal \ r \ n - saya mengerti itu adalah karakter ASCII untuk carriage return mesin ketik (pindah ke awal baris) dan feed baris (pindah ke bawah satu baris). Jadi \ r \ n adalah model "lebih akurat" dari benda fisik dunia nyata untuk karakter garis akhir. Sebelum OS X, Mac menggunakan hanya untuk ini. Saya biasanya menulis semuanya sebagai "pilihan sewenang-wenang yang dibuat dengan terburu-buru yang masih kita hadapi"
Alan Storm

Jawaban:


20

Saya akan menggunakan filedan menyalurkan output ke grep atau awk untuk menemukan file teks, kemudian ekstrak hanya bagian nama file dari fileoutput dan pipa yang ke xargs.

sesuatu seperti:

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

Perhatikan bahwa grep mencari 'teks ASCII' dan bukan 'teks' apa pun - Anda mungkin tidak ingin mengacaukan dokumen Rich Text atau unicode file teks dll.

Anda juga dapat menggunakan find(atau apa pun) untuk menghasilkan daftar file untuk diperiksa dengan file:

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

The -d'\n'argumen untuk xargs membuat xargs memperlakukan setiap input sebagai argumen yang terpisah, sehingga katering untuk nama file dengan spasi dan karakter bermasalah lainnya. yaitu itu alternatif xargs -0ketika sumber input tidak atau tidak dapat menghasilkan output yang NULL dipisahkan (seperti find's -print0pilihan). Menurut changelog, xargs mendapat -d/ --delimiteropsi pada Sep 2005 jadi harus di setiap distro linux yang tidak kuno (saya tidak yakin, itulah sebabnya saya memeriksa - Saya hanya samar-samar ingat itu adalah tambahan "baru").

Perhatikan bahwa umpan baris adalah karakter yang valid dalam nama file, jadi ini akan rusak jika ada nama file yang memiliki umpan baris di dalamnya. Untuk pengguna unix tipikal, ini gila secara patologis, tetapi tidak pernah terdengar jika file tersebut berasal dari Mac atau mesin Windows.

Perhatikan juga bahwa fileitu tidak sempurna. Ini sangat baik dalam mendeteksi tipe data dalam file tetapi kadang-kadang bisa membingungkan.

Saya telah menggunakan banyak variasi metode ini berkali-kali di masa lalu dengan kesuksesan.


1
Terima kasih atas solusi ini! Untuk beberapa alasan filemenampilkan English textdaripada ASCII textpada sistem Solaris saya, jadi saya memodifikasi bagian itu sesuai. Juga, saya diganti awk -F: '{print $1}'dengan yang setara cut -f1 -d:.
Andrew Cheong

3
Layak dikatakan grep -Imenyaring binari
xenoterracide

Mencari kata textharus cukup. Ini juga akan mengambil filedeskripsi seperti ASCII Java program textatau HTML document textatau troff or preprocessor input text.
user1024

Jawaban saya sebagian merupakan respons / peningkatan atas jawaban ini. Poin yang sangat bagus tentang memahami untuk ASCII textmenghindari mengacaukan RTF.
Wildcard

1
xenoterracide: Anda menyelamatkan manusia saya! Just a flag -I dan BINGO
Sergio Abreu

9

Tidak. Tidak ada yang istimewa tentang file biner atau non-biner. Anda dapat menggunakan heuristik seperti 'hanya berisi karakter dalam 0x01-0x7F', tetapi itu akan memanggil file teks dengan file biner karakter non-ASCII, dan file biner file teks yang tidak beruntung.

Sekarang, setelah Anda mengabaikan itu ...

file zip

Jika berasal dari pengguna Windows Anda sebagai file zip, format zip mendukung penandaan file sebagai biner atau teks dalam arsip itu sendiri. Anda dapat menggunakan -aopsi unzip untuk memperhatikan ini dan mengonversi. Tentu saja, lihat paragraf pertama untuk alasan ini mungkin bukan ide yang baik (program zip mungkin telah menebak dengan salah ketika membuat arsip).

zipinfo akan memberi tahu Anda file mana yang biner (b) atau teks (t) dalam daftar zipfile-nya.

file lain

Perintah file akan melihat file dan mencoba mengidentifikasinya. Secara khusus, Anda mungkin akan menemukan -iopsi (tipe output MIME) berguna; hanya mengonversi file dengan jenis teks / *


6

Solusi umum untuk hanya memproses file non-biner dalam bashmenggunakan 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)

Saya menghubungi penulis utilitas file dan dia menambahkan -00paramter bagus di versi 5.26 (dirilis 2016-04-16, misalnya di Arch saat ini dan Ubuntu 16.10) yang mencetak file\0result\0untuk beberapa file sekaligus, dengan cara ini Anda dapat melakukan misalnya:

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

(Bagian awkini untuk menyaring setiap file yang bukan non-biner. ORSAdalah pemisah keluaran.)

Dapat juga digunakan dalam satu lingkaran saja:

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

Berdasarkan ini dan sebelumnya saya membuat bashskrip kecil untuk memfilter file biner yang menggunakan metode baru menggunakan -00parameter filedalam versi yang lebih baru dan jatuh kembali ke metode sebelumnya pada versi yang lebih lama:

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

Atau di sini yang lebih POSIX-y, tetapi membutuhkan dukungan untuk 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

Jawaban yang diterima tidak menemukan semuanya untuk saya. Berikut ini adalah contoh menggunakan grep -Iuntuk mengabaikan binari, dan mengabaikan semua file yang tersembunyi ...

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

Ini dia digunakan dalam aplikasi praktis: dos2unix

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


4

Jawaban Cas baik, tetapi mengasumsikan nama file yang waras ; khususnya diasumsikan bahwa nama file tidak akan mengandung baris baru.

Tidak ada alasan kuat untuk membuat asumsi ini di sini, karena cukup sederhana (dan sebenarnya lebih bersih menurut saya) untuk menangani kasus itu dengan benar juga:

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

The findperintah saja memanfaatkan fitur POSIX yang ditentukan . Menggunakan -execuntuk menjalankan perintah sewenang-wenang karena tes boolean sederhana, kuat (menangani nama file aneh dengan benar), dan lebih portabel daripada -print0.

Faktanya, semua bagian dari perintah ditentukan oleh POSIX kecuali untuk flip.

Catatan yang filetidak menjamin keakuratan hasil yang dikembalikan. Namun, dalam praktiknya memahami "teks ASCII" dalam outputnya cukup dapat diandalkan.

(Mungkin mungkin melewatkan beberapa file teks, tetapi sangat sangat tidak mungkin untuk mengidentifikasi file biner sebagai "teks ASCII" dan memotongnya — jadi kami melakukan kesalahan).


File argumen-kurang callsbisa sangat lambat, misalnya untuk video itu akan memberi tahu Anda semua tentang pengkodean.
phk

Anda juga mengasumsikan tidak ada file yang dimulai -.
phk

Dan saya tidak melihat alasan mengapa Anda tidak hanya melakukan satu panggilan saja file, dapat mengambil beberapa file sebagai argumen.
phk

@ php, untuk mengatasi komentar Anda: (1) ada baiknya mengetahui potensi kelambatan, tapi saya tidak melihat cara POSIX untuk mencegahnya; (2) Saya membuat asumsi nol tentang nama file, karena findperintah akan awalan ./ke nama file apa pun yang diteruskan ke perintah shell; (3) Menggunakan grepsebagai tes pada fileoutput perintah tunggal pada satu waktu adalah satu-satunya cara POSIX yang bisa saya lihat untuk menjamin penanganan nama file yang benar yang mungkin berisi baris baru.
Wildcard

Saya melihat ke solusi "POSIX-y" terakhir Anda dan saya pikir ini cerdas - tetapi Anda menganggap itu filemendukung --mime-encodingflag dan --separator, yang keduanya tidak dijamin oleh POSIX .
Wildcard

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

Ini akan menemukan semua file biasa ( -type f) di direktori saat ini (atau di bawah) yang grepdianggap tidak kosong dan non-biner.

Ini digunakan grep -Iuntuk membedakan antara file biner dan non-biner. The -Ibendera dan akan menyebabkan grepuntuk keluar dengan status keluar non-nol ketika mendeteksi bahwa file biner. File "biner", menurutnya grep, adalah file yang berisi karakter di luar rentang ASCII yang dapat dicetak.

The -qpilihan untuk grepakan menyebabkan ia berhenti dengan status nol keluar jika pola yang diberikan ditemukan, tanpa memancarkan data. Pola yang kami gunakan adalah satu titik, yang akan cocok dengan karakter apa pun.

Jika file ditemukan non-biner dan jika mengandung setidaknya satu karakter, nama file tersebut dicetak.

Jika Anda merasa berani, Anda dapat menghubungkannya flip -ujuga:

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

1

Coba ini :

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

Dimana argumennya grep '[^ -~]'adalah '[^<tab><space>-~]'.

Jika Anda mengetikkannya pada baris perintah shell, ketikkan Ctrl+ Vsebelumnya Tab. Dalam editor, seharusnya tidak ada masalah.

  • '[^<tab><space>-~]'akan cocok dengan karakter apa pun yang bukan teks ASCII (carriage return diabaikan oleh grep).
  • -L hanya akan mencetak nama file file yang tidak cocok
  • -Zakan menampilkan nama file yang dipisahkan dengan karakter nol (untuk xargs -0)

Perlu dicatat bahwa dengan Perl-seperti Regex grep -P(jika tersedia) \ttersedia. Atau, gunakan terjemahan lokal jika shell mendukungnya: $'\t'( bashdan zshlakukan).
phk

1

Solusi alternatif:

Perintah dos2unix akan mengubah akhir baris dari Windows CRLF ke Unix LF, dan secara otomatis melewatkan file biner. Saya menerapkannya secara rekursif menggunakan:

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

Karena dos2unixdapat menggunakan beberapa nama file sebagai argumen, jauh lebih efisien untuk melakukannyafind . -type f -exec dos2unix {} +
Anthon

0

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

i. (-type f -and -path '* / git / *' -iname 'README'): mencari file dalam jalur yang berisi nama git dan file dengan nama README. Jika Anda tahu folder dan nama file tertentu yang akan dicari, akan berguna.

Perintah ii.-exec menjalankan perintah pada nama file yang dihasilkan oleh find

aku aku aku.\; menunjukkan akhir dari perintah

iv. {} adalah output dari file / nama pengguna yang ditemukan dari pencarian pencarian sebelumnya

v. Beberapa perintah dapat dijalankan selanjutnya. Dengan menambahkan -exec "command" \; seperti dengan -exec flip -u \;

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. 

Anda dapat mengkloning direktori tes ini dan mencobanya: https://github.com/alphaCTzo7G/stackexchange/tree/master/linux/findSolution204092017

jawaban lebih rinci di sini: https://github.com/alphaCTzo7G/stackexchange/blob/master/linux/findSolution204092017/README.md

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.