Looping sobre uma pasta entre de qualquer maneira o loop

3

Ao fazer o loop em uma pasta por meio de um

for f in $path 

Estou com um comportamento inesperado, ou seja, os loops são inseridos mesmo que nenhum arquivo corresponda ao caractere curinga. Eu estou usando cygwin e este é o meu código

#!/bin/sh
here=$(pwd)
release(){
    release="$1"
    targetdisk="$2"
    package="$3"
    searchPath="../$package/${package}Setup/*/*/*.msi"
    echo $searchPath
    ls $searchPath
    for f in $searchPath; do
        mode=$(echo $file | sed -e 's:.*/.*/\(.*\)/.*\.msi::')
        version=$(echo $file | sed -e 's:.*/\(.*\)/.*/*.\.msi::')
        PREVIOUSIFS=$IFS
        IFS=#
        targetPath="$targetdisk:\Software and tools\Install\$release"
        newFile="$targetPath\$package-$mode-$release.exe"
        if [ ! -d "$targetPath" ]; then
            mkdir -p "$targetPath"
        fi
        echo $newFile
        echo $f


        #cp $file $newFile
        IFS=$PREVIOUSIFS
    done;
}
release $1 $2 MyStuff

Eu coloquei um propósito MyStuff, que não existe:

$ ./release.sh 1.0-dev G
../MyStuff/MyStuffSetup/*/*/*.msi
ls: ../MyStuff/MyStuffSetup/*/*/*.msi: No such file or directory
G:\Software and tools\Install.0-dev\MyStuff--1.0-dev.exe
../MyStuff/MyStuffSetup/*/*/*.msi

Como você pode ver, os dois ecos são executados. Por que isso acontece mesmo que não haja correspondência?

    
por Edmondo1984 29.07.2013 / 19:01

2 respostas

7

Um padrão de curinga que não corresponde a nenhum arquivo é deixado sem ser expandido. A intenção é permitir a digitação de um argumento para um comando que contenha caracteres curinga, mas não seja um padrão. Isso faz um pouco de sentido na linha de comando, onde permite salvar dois caracteres de aspas ocasionalmente. Em um script, é muito chato. Infelizmente, não há como alterar esse comportamento no sh tradicional. Você pode verificar se o padrão não foi expandido.

for f in "../$package/${package}Setup"/*/*/*.msi; do
  if [ "$f" = "../$package/${package}Setup"/*/*/*.msi" ]; then
    # No match
    break
  fi
  …
done

O Bash pode ser instruído para expandir um padrão curinga não correspondente para a lista vazia. Mude sua linha shebang para #!/bin/bash , e você pode fazer isso:

shopt -s nullglob
for f in "../$package/${package}Setup"/*/*/*.msi; do
  …

Existem outros problemas no seu script. A maneira como você usa a variável searchPath será interrompida se houver espaços ou caracteres curinga (incluindo barras invertidas) em $package . Não deixe as substituições da variável $searchPath sem aspas. Sempre use aspas duplas em torno das substituições de variáveis, a menos que você queira que elas sejam tratadas como uma lista de padrões separada por espaço em branco, o que não é o caso aqui - $package é uma string (exigindo aspas duplas) enquanto o aparente * faz o lote um padrão de curinga. Coloque o padrão diretamente no loop for , como acima.

Para registro, em vez destes comandos echo (que não possuem aspas duplas em torno das substituições de variáveis, então os argumentos serão desconfigurados), use set -x para exibir cada comando no stderr conforme ele é executado.

Em algum ponto do script, você está definindo IFS=# , mas nunca está dividindo em # . Não defina IFS se você não for usá-lo.

Existem vários problemas com mode=$(echo $file | sed -e 's:.*/.*/\(.*\)/.*\.msi::') . Como explicado acima, faltam aspas duplas em torno de "$file" . Além disso, chamar um sed extra para cada arquivo a ser processado é lento (a execução de processos externos é lenta no Cygwin) e excessivamente complexa. O shell tem construções de processamento de string; enquanto eles são primitivos, eles são suficientes aqui. Seu

dir="${file%/*}"
mode="${dir##*/}"
dir="${dir%/*}"
version="${dir##*/}"
    
por 30.07.2013 / 03:14
5

Esse script tem vários problemas, mas o comportamento que você está perguntando, por que o loop é executado, é o seguinte:

Na construção do shell

for f in <expr>; do <commands>; done

um padrão de arquivo é frequentemente usado para "expr", que é então substituído por globalização de nome de arquivo de shell, e foi isso que você fez. Mas sua expressão não combina com nada, então globbing não a expande em uma lista de caminhos de arquivos. Mas também não é uma lista de comprimento zero (null) como em muitas outras linguagens, mas é a expressão de caminho com os asteriscos que você ecoa logo acima do loop. Então o loop é executado uma vez, com $ f set igual à string unexpanded terminando em * .msi. Você pode ver isso onde você faz eco antes do loop. Sabemos que isso não combina com nada porque você também o utiliza com ls, e é por isso que você obtém o erro "Não existe arquivo ou diretório".

(Note também que você usa $ arquivo no loop, e eu acho que você quer usar $ f lá.

    
por 29.07.2013 / 19:19