Obter todos os arquivos, exceto os arquivos em array - Bash

5

Eu sou obrigado a escrever um utilitário único que faz alguma operação em todos os arquivos em um determinado diretório, mas uma lista de arquivos em uma lista pré-definida. Como a lista fornecida é pré-definida, vou codificá-la como uma matriz.

Dito isto, como obter nomes de todos os arquivos que não estão na matriz especificada? Isso pode estar em qualquer script unix padrão (bash, awk, perl).

    
por Kannan Ramamoorthy 10.08.2017 / 13:55

3 respostas

6

Com bash , você poderia fazer:

all=(*)
except=(file1 file2 notme.txt)
only=()
IFS=/
for file in "${all[@]}"; do
  case "/${except[*]}/" in
    (*"/$file/"*) ;;     # do nothing (exclude)
    (*) only+=("$file")  # add to the array
  esac
done
ls -ld -- "${only[@]}"

(que funciona aqui para os arquivos no diretório atual, mas não de forma confiável para globs como all=(*/*) except=(foo/bar) , pois usamos / para unir os elementos da matriz para a pesquisa).

Baseia-se no fato de que "${array[*]}" une os elementos da matriz com o primeiro caractere de $IFS (aqui escolhido como / , como não pode ocorrer em um arquivo nome ; NUL é um caracter que não pode ocorrer em um arquivo caminho , mas infelizmente bash (ao contrário de zsh ) não pode ter tal caractere em suas variáveis). Portanto, para cada arquivo em $all (aqui com $file sendo foo como exemplo), fazemos um case "/file1/file2/notme.txt/" in (*"/foo/"*) para verificar se $file deve ser excluído.

    
por 10.08.2017 / 14:13
5

É mais fácil com zsh :

except=(file1 file2 notme.txt)
all=(*)
only=(${all:|except})
ls -ld -- $only

Mnemônico para ${all:|except} : elementos de $all bar aqueles de $except .

Você também pode verificar se os arquivos estão no array $except como parte de um qualifier glob :

ls -ld -- *.txt(^e:'((except[(Ie)$REPLY]))':)

Ou usando uma função:

in_except() ((except[(Ie)${1-$REPLY}]))
ls -ld -- *.txt(^+in_except)
    
por 10.08.2017 / 14:01
3

Se os nomes dos arquivos forem simples o suficiente, você pode usar a variável GLOBIGNORE do bash :

The GLOBIGNORE shell variable may be used to restrict the set of filenames matching a pattern. If GLOBIGNORE is set, each matching filename that also matches one of the patterns in GLOBIGNORE is removed from the list of matches. If the nocaseglob option is set, the matching against the patterns in GLOBIGNORE is performed without regard to case. The filenames . and .. are always ignored when GLOBIGNORE is set and not null. However, setting GLOBIGNORE to a non-null value has the effect of enabling the dotglob shell option, so all other filenames beginning with a ‘.’ will match. To get the old behavior of ignoring filenames beginning with a ‘.’, make ‘.*’ one of the patterns in GLOBIGNORE. The dotglob option is disabled when GLOBIGNORE is unset.

$ echo *
bin boot dev etc home lib lib64 lost+found mnt opt proc root run sbin srv sys tmp usr var
$ except=(etc lib lib64 tmp sbin)
$ GLOBIGNORE=$(IFS=:; printf "%s" "${except[*]}")
$ echo *
bin boot dev home lost+found mnt opt proc root run srv sys usr var

É claro que, se você estiver criando a matriz, poderá definir diretamente a variável GLOBIGNORE :

GLOBIGNORE=etc:lib:lib64:tmp:sbin

Você também pode tirar proveito de quaisquer padrões que possam estar na lista e que se ajustem a curingas comuns:

GLOBIGNORE=etc:lib*:tmp:sbin
    
por 10.08.2017 / 15:55