GNU/Linux >> Znalost Linux >  >> Linux

Iterujte seznam souborů s mezerami

Existuje také velmi jednoduché řešení:spolehnout se na bash globbing

$ mkdir test
$ cd test
$ touch "stupid file1"
$ touch "stupid file2"
$ touch "stupid   file 3"
$ ls
stupid   file 3  stupid file1     stupid file2
$ for file in *; do echo "file: '${file}'"; done
file: 'stupid   file 3'
file: 'stupid file1'
file: 'stupid file2'

Všimněte si, že si nejsem jistý, zda je toto chování výchozí, ale v mém obchodě nevidím žádné speciální nastavení, takže bych řekl, že by to mělo být "bezpečné" (testováno na osx a ubuntu).


Existuje několik funkčních způsobů, jak toho dosáhnout.

Pokud se chcete držet své původní verze, můžete to udělat takto:

getlist() {
        IFS=$'\n'
        for file in $(find . -iname 'foo*') ; do
                printf 'File found: %s\n' "$file"
        done
}

To stále selže, pokud názvy souborů obsahují doslovné nové řádky, ale mezery to neporuší.

Není však nutné zasahovat do IFS. Zde je můj preferovaný způsob, jak to udělat:

getlist() {
    while IFS= read -d $'\0' -r file ; do
            printf 'File found: %s\n' "$file"
    done < <(find . -iname 'foo*' -print0)
}

Pokud najdete < <(command) syntaxe neznámá, měli byste si přečíst o substituci procesů. Výhoda oproti for file in $(find ...) je, že soubory s mezerami, novými řádky a dalšími znaky jsou správně zpracovány. To funguje, protože find s -print0 použije null (také znám jako \0 ) jako terminátor pro každý název souboru a na rozdíl od nového řádku není null v názvu souboru povoleným znakem.

Výhoda oproti téměř ekvivalentní verzi

getlist() {
        find . -iname 'foo*' -print0 | while read -d $'\0' -r file ; do
                printf 'File found: %s\n' "$file"
        done
}

Je to, že jakékoli přiřazení proměnných v těle cyklu while je zachováno. To znamená, že pokud přejdete na while jako výše, pak tělo while je v podskořápce, která nemusí být to, co chcete.

Výhoda verze procesní substituce oproti find ... -print0 | xargs -0 je minimální:xargs verze je v pořádku, pokud vše, co potřebujete, je vytisknout řádek nebo provést jednu operaci se souborem, ale pokud potřebujete provést více kroků, je verze se smyčkou jednodušší.

UPRAVIT :Zde je pěkný testovací skript, abyste si mohli udělat představu o rozdílu mezi různými pokusy o vyřešení tohoto problému

#!/usr/bin/env bash

dir=/tmp/getlist.test/
mkdir -p "$dir"
cd "$dir"

touch       'file not starting foo' foo foobar barfoo 'foo with spaces'\
    'foo with'$'\n'newline 'foo with trailing whitespace      '

# while with process substitution, null terminated, empty IFS
getlist0() {
    while IFS= read -d $'\0' -r file ; do
            printf 'File found: '"'%s'"'\n' "$file"
    done < <(find . -iname 'foo*' -print0)
}

# while with process substitution, null terminated, default IFS
getlist1() {
    while read -d $'\0' -r file ; do
            printf 'File found: '"'%s'"'\n' "$file"
    done < <(find . -iname 'foo*' -print0)
}

# pipe to while, newline terminated
getlist2() {
    find . -iname 'foo*' | while read -r file ; do
            printf 'File found: '"'%s'"'\n' "$file"
    done
}

# pipe to while, null terminated
getlist3() {
    find . -iname 'foo*' -print0 | while read -d $'\0' -r file ; do
            printf 'File found: '"'%s'"'\n' "$file"
    done
}

# for loop over subshell results, newline terminated, default IFS
getlist4() {
    for file in "$(find . -iname 'foo*')" ; do
            printf 'File found: '"'%s'"'\n' "$file"
    done
}

# for loop over subshell results, newline terminated, newline IFS
getlist5() {
    IFS=$'\n'
    for file in $(find . -iname 'foo*') ; do
            printf 'File found: '"'%s'"'\n' "$file"
    done
}


# see how they run
for n in {0..5} ; do
    printf '\n\ngetlist%d:\n' $n
    eval getlist$n
done

rm -rf "$dir"

Iteraci založenou na slovech můžete nahradit iterací založenou na řádcích:

find . -iname "foo*" | while read f
do
    # ... loop body
done

Linux
  1. Najít soubory a rozbalit je (s mezerami)

  2. Vypsat všechny soubory grafických obrázků s find?

  3. vypsat/najít všechny běžné soubory ve všech podadresářích s výjimkou binárních souborů

  1. Najděte soubory a adresáře v Linuxu pomocí příkazu find

  2. Jak v Linuxu zobrazím seznam souborů s úplnými cestami?

  3. Zkontrolujte využití disku u souborů vrácených s mezerami

  1. Procházení souborů s mezerami v názvech?

  2. Jak najít všechny soubory s velikostí souboru nula (0) bajtů v adresáři rekurzivně

  3. Jak mohu v Linuxu vygenerovat seznam souborů s jejich absolutní cestou?