GNU/Linux >> Znalost Linux >  >> Linux

Proč je Looping Over Find Output špatným postupem?

Tato otázka je inspirována

Proč je používání shellové smyčky ke zpracování textu považováno za špatný postup?

Vidím tyto konstrukce

for file in `find . -type f -name ...`; do smth with ${file}; done

a

for dir in $(find . -type d -name ...); do smth with ${dir}; done

jsou zde používány téměř denně, i když si někteří lidé najdou čas na komentování těchto příspěvků a vysvětlují, proč je třeba se takovým věcem vyhnout...
Když vidím počet takových příspěvků (a skutečnost, že někdy jsou tyto komentáře prostě ignored) Myslel jsem, že bych mohl položit otázku:

Proč je smyčka přes find špatný postup výstupu a jaký je správný způsob spuštění jednoho nebo více příkazů pro každý název/cestu souboru vrácenou find ?

Přijatá odpověď:

Problém

for f in $(find .)

spojuje dvě neslučitelné věci.

find vytiskne seznam cest k souborům oddělených znaky nového řádku. Zatímco operátor split+glob, který se vyvolá, když opustíte $(find .) unquoted v kontextu tohoto seznamu jej rozdělí na znaky $IFS (ve výchozím nastavení zahrnuje nový řádek, ale také mezeru a tabulátor (a NUL v zsh )) a u každého výsledného slova provede globbing (kromě zsh). ) (a dokonce i expanze složené závorky v derivátech ksh93 nebo pdksh!).

I když to zvládnete:

IFS='
' # split on newline only
set -o noglob # disable glob (also disables brace expansion in pdksh
              # but not ksh93)
for f in $(find .) # invoke split+glob

To je stále špatně, protože znak nového řádku je platný jako kterýkoli znak v cestě k souboru. Výstup příkazu find -print jednoduše nelze spolehlivě dodatečně zpracovat (kromě použití nějakého spletitého triku, jak je uvedeno zde ).

To také znamená, že shell potřebuje uložit výstup find úplně a pak to rozdělit+globovat (což znamená uložit tento výstup podruhé do paměti), než začnete procházet soubory.

Všimněte si, že find . | xargs cmd má podobné problémy (mezery, nový řádek, jednoduché uvozovky, dvojité uvozovky a zpětné lomítko (a s některými xarg implementační bajty netvořící součást platných znaků) jsou problémem)

Správnější alternativy

Jediný způsob, jak použít for smyčka na výstupu find by bylo použít zsh který podporuje IFS=$'

Linux
  1. Ssh – Proč je Firefox tak pomalý oproti Ssh?

  2. Proč mi Grep -o -w neposkytuje očekávaný výkon na Mac OS X?

  3. Proč dochází k výstupu příkazu Ping po jeho ukončení?

  1. Jak smyčkovat adresáře v Linuxu?

  2. Iterujte seznam souborů s mezerami

  3. Výstup příkazu Linux jako parametr jiného příkazu

  1. Proč Find nepřijímá ‚-exec Cp {} Dir +‘?

  2. Podrobný výstup příkazu Bash find

  3. Je sudo su - považováno za špatný postup?