encontrar com variáveis do usuário

1

Estou tentando chamar o find com algumas variáveis. Até agora eu tive isso:

DIRECTORY="./ "
FILENAME=-regex" .*test.*"
find $DIRECTORY $FILENAME

O que funciona bem. Se eu mudar o nome do arquivo para:

FILENAME=-regex" .*"

para listar todos os arquivos no diretório, recebo um erro:

find: paths must precede expression: ..

O que estou fazendo de errado?

    
por Bartlomiej Lewandowski 27.10.2012 / 15:17

3 respostas

1

O conteúdo da variável FILENAME é

-regex .*test.*

As aspas não fazem parte do valor da variável, elas fazem parte da sintaxe do shell. O shell analisou a linha, interpretando as citações, antes mesmo de ver que era uma atribuição.

Quando você executa a linha find $DIRECTORY $FILENAME , $FILENAME é primeiro substituído por seu valor. Em seguida, o shell executa duas etapas de expansão no valor da variável: divide-a em palavras separadas, onde a variável contém espaço em branco (que você deseja) e executa globbing (ou seja, expansão curinga) em cada palavra, portanto .* é expandido para a lista de nomes de arquivos no diretório atual que começam com um ponto.

Você não teve problemas com o primeiro snippet porque o padrão .*test.* não coincidiu com nenhum arquivo, por isso expandiu para si mesmo.

A solução robusta é usar uma variável de array em vez de uma variável de string quando você precisa armazenar várias palavras.

DIRECTORY="./"
EXPRESSION=("-regex" ".*test.*")
find "$DIRECTORY" "${EXPRESSION[@]}"

ou se você quiser permitir vários diretórios:

DIRECTORIES=("./")
EXPRESSION=("-regex" ".*test.*")
find "${DIRECTORIES[@]}" "${EXPRESSION[@]}"

"${EXPRESSION[@]}" expande para a lista de elementos na matriz, em palavras separadas.

Note que você deve sempre usar aspas duplas em torno das substituições de variáveis "$foo" e do comando susbtitutions "$(foo)" , a menos que você queira que a divisão de palavras e globbing aconteçam com os valores.

Aqui, como você está usando o bash, um array é a solução certa. Em um shell que não possui arrays, existem várias possibilidades. Você pode usar os parâmetros posicionais, que são efetivamente uma variável de matriz, mas isso é apenas uma possibilidade se você não estiver usando-os para outra coisa:

set -- "./"                  # start with the directory
set -- "$@" -regex '.*'      # add the expression
find "$@"                    # go

Outro método é citar corretamente o conteúdo da variável para prepará-lo para a divisão posterior de palavras e globbing. Você pode usar uma barra invertida antes de um caractere curinga ( ?*[ ) para fazê-lo ser interpretado literalmente.

DIRECTORY=./
EXPRESSION='-regex .\*'
find "$DIRECTORY" $EXPRESSION

Outro método é desativar o globbing com set -f . antes de executar a linha find . Certifique-se de ligá-lo novamente com set +f se você precisar dele depois. Observe que, como você está usando a divisão de palavras, não poderá colocar caracteres de espaço em branco como parte de um argumento para um predicado find .

DIRECTORY=./
EXPRESSION='-regex .*'
set -f
find "$DIRECTORY" $EXPRESSION

Veja também estou tentando colocar um comando em uma variável, mas os casos complexos sempre falham! no bash FAQ.

    
por 28.10.2012 / 02:02
0

Ou

directory=.
match=(-regex '.*test.*')
find "$directory" "${match[@]}"

Ou (usando aqui "," apenas para destacar):

directory=.
match='-regex,.*test.*'
IFS=,
set -f
find "$directory" $match

Ou:

directory=.
match="-regex '.*test.*'"
eval 'find "$directory" '"$match"
    
por 27.10.2012 / 19:04
-1

Você não está citando as variáveis. Portanto, o que a shell vê é

find ./  -regex .*

E expande .* para . .. .

    
por 27.10.2012 / 15:29