it-swarm-eu.dev

Nalezení všech souborů "Non-Binary"

Je možné pomocí příkazu find najít všechny „ne-binární“ soubory v adresáři? Tady je problém, který se snažím vyřešit.

Obdržel jsem archiv souborů od uživatele systému Windows. Tento archiv obsahuje zdrojový kód a obrazové soubory. Náš systém sestavení nehraje Nice se soubory, které mají zakončení oken Windows. Mám program příkazového řádku (flip -u), které převrátí konce čar mezi * nix a okny. Takže bych rád něco takového udělal

find . -type f | xargs flip -u

Pokud je však tento příkaz spuštěn proti obrazovému souboru nebo jinému binárnímu mediálnímu souboru, bude soubor poškozen. Uvědomuji si, že bych mohl sestavit seznam přípon souborů a filtrovat s tím, ale raději bych měl něco, co se nespoléhá na mě, abych tento seznam aktualizoval.

Existuje tedy způsob, jak najít všechny nebinární soubory ve stromu adresářů? Nebo existuje alternativní řešení, které bych měl zvážit?

46
Alan Storm

Použil bych file a vložil výstup do grep nebo awk, abych našel textové soubory, pak extrahoval jen část názvu souboru z výstupu file a vložil jej do xargs.

něco jako:

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

Všimněte si, že grep vyhledává spíše „text ASCII“ než jakýkoli „text“ - pravděpodobně nebudete chtít komunikovat s dokumenty Rich Text nebo textovými soubory unicode atd.

Můžete také použít find (nebo cokoli) k vygenerování seznamu souborů, které chcete prozkoumat pomocí file:

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

Argument -d'\n' Pro xargs způsobí, že xargs zachází s každým vstupním řádkem jako se samostatným argumentem, čímž zásobuje názvy souborů mezerami a dalšími problematickými znaky. tj. je to alternativa k xargs -0, pokud vstupní zdroj negeneruje nebo nemůže vygenerovat výstup oddělený NULL (jako je například možnost -print0find). Podle changelogu dostali xargs v září 2005 možnost -d/--delimiter, Takže by měla být v jakékoli nestarší linuxové distro (nebyl jsem si jistý, což je důvod, proč jsem to zkontroloval - jen jsem vágně si pamatoval, že to byl „nedávný“ dodatek).

Všimněte si, že řádek je platný znak v názvech souborů, takže pokud se v souborech budou vyskytovat řádky, bude to přerušeno. Pro typické unixové uživatele je to patologicky šílené, ale není neslýchané, zda soubory pocházejí z počítačů Mac nebo Windows.

Také si všimněte, že file není dokonalý. Je velmi dobré detekovat typ dat v souboru, ale občas se mohou zmást.

V minulosti jsem s úspěchem použil řadu variací této metody.

21
cas

Ne. O binárním nebo ne-binárním souboru není nic zvláštního. Můžete použít heuristiku jako „obsahuje pouze znaky v 0x01–0x7F“, ale to bude volat textové soubory s binárními soubory, které nejsou znaky ASCII, a nešťastné binární soubory.

Jakmile jste to ignorovali ...

Soubory ZIP

Pokud pochází od uživatele Windows jako soubor Zip, formát Zip podporuje označování souborů jako samotného binárního nebo textového archivu. Můžete použít unzip's -a možnost věnovat pozornost tomuto a převést. Samozřejmě, viz první odstavec, proč to nemusí být dobrý nápad (program Zip se mohl při vytvoření archivu uhodnout špatně).

zipinfo vám řekne, které soubory jsou binární (b) nebo text (t) v seznamu zipfile.

ostatní soubory

Příkaz file se podívá na soubor a pokusí se jej identifikovat. Konkrétně pravděpodobně najdete jeho -i (typ výstupu MIME) užitečná; převádějte pouze soubory s typovým textem/*

9
derobert

Přijatá odpověď pro mě všechny nenašla. Zde je příklad použití grep's -I ignorovat binární soubory a ignorovat všechny skryté soubory ...

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

Zde se používá v praktické aplikaci: dos2unix

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

8
phyatt

Obecné řešení pro zpracování pouze binárních souborů v bash pomocí 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)

Kontaktoval jsem autora nástroje file a přidal šikovný -00 paramter ve verzi 5.26 (vydáno 2016-04-16, je např. v aktuálním Arch a Ubuntu 16.10), který tiskne file\0result\0 pro více souborů, které jsou do něj přidány najednou, takto můžete například:

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

(Část awk je odfiltrovat každý soubor, který není binární. ORS je výstupní oddělovač.)

Lze samozřejmě také použít ve smyčce:

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

Na základě tohoto a předchozího jsem vytvořil malý bash skript pro odfiltrování binárních souborů, které využívají novou metodu pomocí -00 parametr file v jeho novějších verzích a ve starších verzích se vrací k předchozí metodě:

#!/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 -- "[email protected]" |
    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

Nebo zde více POSIX-y, ale vyžaduje podporu pro 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 -- "[email protected]" |
    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
7
phk
find . -type f -exec grep -I -q . {} \; -print

Najdete zde všechny běžné soubory (-type f) v aktuálním adresáři (nebo níže), které grep považuje za neprázdné a ne-binární.

Používá grep -I k rozlišení mezi binárními a ne-binárními soubory. The -I flag a způsobí ukončení grep se stavem nenulového ukončení, když zjistí, že soubor je binární. "Binární" soubor je podle grep soubor, který obsahuje znak mimo rozsah tisku ASCII).

The -q možnost grep způsobí, že skončí se stavem nulového ukončení, pokud je daný vzor nalezen, bez emise dat. Vzor, který používáme, je jedna tečka, která bude odpovídat libovolnému znaku.

Pokud se zjistí, že soubor není binární a obsahuje alespoň jeden znak, vytiskne se název souboru.

Pokud se cítíte stateční, můžete připojit svůj flip -u do toho také:

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

Casova odpověď je dobrá, ale předpokládá rozumné názvy souborů; zejména se předpokládá, že názvy souborů nebudou obsahovat nové řádky.

Neexistuje žádný dobrý důvod k tomu, aby byl tento předpoklad proveden zde, protože je docela jednoduché (a podle mého názoru ve skutečnosti čistší), aby se s tímto případem zacházelo také správně:

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

Příkaz find používá pouze funkce určené pro POSIX . Použitím -exec spouštět libovolné příkazy, protože booleovské testy jsou jednoduché, robustní (správně zpracovává liché názvy souborů) a přenosnější než -print0.

Ve skutečnosti jsou všechny části příkazu specifikovány POSIXem kromě flip.

Všimněte si, že file nezaručuje přesnost výsledků, které vrací. V praxi je však grepování „ASCII textu“ ve svém výstupu docela spolehlivé.

(Mohlo by to chybět některé textové soubory, ale je velmi nepravděpodobné, že by binární soubor nesprávně identifikoval jako „text ASCII“ a upravil jej - takže jsme ering na straně opatrnosti.)

4
Wildcard

Zkuste to :

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

Kde argument grep '[^ -~]' je '[^<tab><space>-~]'.

Pokud jej zadáte do příkazového řádku Shell, zadejte Ctrl+V před Tab. V editoru by neměl být žádný problém.

  • '[^<tab><space>-~]' bude odpovídat libovolnému znaku, který není ASCII text (návraty konce řádku jsou ignorovány grep).
  • -L vytiskne pouze název souboru, který se neshoduje
  • -Z vydá názvy souborů oddělené nulovým znakem (pro xargs -0)
1
Vouze

Alternativní řešení:

Příkaz dos2unix převede konce řádků z Windows CRLF na Unix LF a automaticky přeskočí binární soubory. Aplikuji to rekurzivně pomocí:

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

Sudo najít/(- typ f - a - cesta '*/ git /*' -jmenovat 'README') -exec grep -liI '100644\| 100755 '{} \; -exec flip -u {} \;

i. (-typ f - a - cesta '*/ git /*' - jméno 'README'): hledá soubory v cestě obsahující jméno git a soubor s názvem README. Pokud znáte nějakou konkrétní složku a název souboru, který chcete vyhledat, bude to užitečné.

příkaz ii.-exec spustí příkaz na název souboru generovaný příkazem find

iii. \; označuje konec příkazu

iv. {} je výstup názvu souboru/složky nalezeného z předchozího hledání

v.Multiple příkazy lze spustit následně. Připojením -exec "příkaz" \; například s -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. 

můžete tento testovací adresář klonovat a vyzkoušet: https://github.com/alphaCTzo7G/stackexchange/tree/master/linux/findSolution204092017

podrobnější odpověď zde: https://github.com/alphaCTzo7G/stackexchange/blob/master/linux/findSolution204092017/README.md

0
alpha_989