Como lidar corretamente com expansão de curinga em um script de shell bash?

votos
3
#!/bin/bash

hello()
{
    SRC=$1
    DEST=$2

    for IP in `cat /opt/ankit/configs/machine.configs` ; do
        echo $SRC | grep '*' > /dev/null
        if test `echo $?` -eq 0 ; then
            for STAR in $SRC ; do
                echo -en $IP
                echo -en \n\t ARG1=$STAR ARG2=$2\n\n
            done
        else
            echo -en $IP
            echo -en \n\t ARG1=$SRC ARG2=$DEST\n\n
        fi
    done
}

hello $1 $2

A descrição acima é o shell script que eu fornecer fonte (SRC) & desitnation caminho (DEST). Funcionou muito bem quando eu não colocou em um caminho SRC com wild card ' '. Quando eu executar este script shell e dar ' ' .pdf ou '*' como se segue:

root@ankit1:~/as_prac# ./test.sh /home/dev/Examples/*.pdf /ankit_test/as

Eu recebo o seguinte resultado:

192.168.1.6
ARG1=/home/dev/Examples/case_Contact.pdf ARG2=/home/dev/Examples/case_howard_county_library.pdf

O DEST é / ankit_test / as, mas DEST também obter manupulated devido a '*'. A resposta esperada é

ARG1=/home/dev/Examples/case_Contact.pdf ARG2=/ankit_test/as

Então, se você entender o que estou tentando fazer, por favor me ajude a resolver este bug. Eu vou ser grato a você.

Desde já, obrigado!!!

Eu preciso saber exatamente como eu usar '* .pdf' no meu um programa por um sem perturbar DEST.

Publicado 03/11/2008 em 08:31
fonte usuário
Em outras línguas...                            


9 respostas

votos
3

O shell irá expandir curingas a menos que você escapar-lhes, por exemplo, se você tem

$ ls
one.pdf two.pdf three.pdf

e executar o seu script como

./test.sh *.pdf /ankit__test/as

será o mesmo que

./test.sh one.pdf two.pdf three.pdf /ankit__test/as

o que não é o que você espera. fazendo

./test.sh \*.pdf /ankit__test/as

Deveria trabalhar.

Respondeu 03/11/2008 em 08:47
fonte usuário

votos
1

Você também está faltando uma final "feito" para fechar o seu exterior para loop.

Respondeu 03/11/2008 em 08:52
fonte usuário

votos
0

Não há necessidade de gerar um shell de olhar para a $?variável, você pode avaliá-lo diretamente.

Deve ser apenas:

if [ $? -eq 0 ]; then
Respondeu 03/11/2008 em 08:59
fonte usuário

votos
4

Seu script precisa de mais trabalho. Mesmo depois de escapar do curinga, você não terá a sua resposta esperada. Você vai ter:

ARG1=/home/dev/Examples/*.pdf ARG2=/ankit__test/as

Tente o seguinte em vez disso:

for IP in `cat /opt/ankit/configs/machine.configs`
do
    for i in $SRC
    do
        echo -en "$IP"
        echo -en "\n\t ARG1=$i ARG2=$DEST\n\n"
    done
done

Executá-lo como este:

root@ankit1:~/as_prac# ./test.sh "/home/dev/Examples/*.pdf" /ankit__test/as
Respondeu 03/11/2008 em 09:40
fonte usuário

votos
1

OK, isso parece fazer o que quiser:

#!/bin/bash

hello() {

  SRC=$1
  DEST=$2

   while read IP ; do
     for FILE in $SRC; do
       echo -e "$IP"
       echo -e "\tARG1=$FILE ARG2=$DEST\n"
      done
   done < /tmp/machine.configs
 }

 hello "$1" $2
  1. Você ainda precisa escapar quaisquer caracteres curinga quando você chamar o script
  2. As aspas são necessárias quando você invocar a hellofunção, caso contrário, o simples fato de avaliar $1causas do curinga para ser expandido, mas não queremos que isso aconteça até $SRCé atribuído na função
Respondeu 03/11/2008 em 09:47
fonte usuário

votos
2

Se você puder, alterar a ordem dos parâmetros passados ​​para o seu script shell da seguinte forma:

./test.sh /ankit_test/as /home/dev/Examples/*.pdf

Isso tornaria a sua vida muito mais fácil desde que a parte variável se move para o fim da linha. Em seguida, o script a seguir irá fazer o que quiser:

#!/bin/bash
hello()
{
    SRC=$1
    DEST=$2

    for IP in `cat /opt/ankit/configs/machine.configs` ; do
        echo -en "$IP"
        echo -en "\n\t ARG1=$SRC ARG2=$DEST\n\n"
    done
}

arg2=$1
shift
while [[ "$1" != "" ]] ; do
        hello $1 $arg2
        shift
done
Respondeu 03/11/2008 em 10:00
fonte usuário

votos
1

Aqui está o que eu vim com:

#!/bin/bash

hello()
{
    # DEST will contain the last argument
    eval DEST=\$$#

    while [ $1 != $DEST ]; do
        SRC=$1

        for IP in `cat /opt/ankit/configs/machine.configs`; do
            echo -en "$IP"
            echo -en "\n\t ARG1=$SRC ARG2=$DEST\n\n"
        done

        shift || break
    done
}

hello $*

Em vez de passar apenas dois parâmetros para a função Olá (), vamos passar em todos os argumentos que o script tem.

Dentro da função Olá (), primeiro atribuir o argumento final para o DEST var. Em seguida, percorrer todos os argumentos, atribuindo a cada um para SRC, e executar tudo o que ordena que queremos usar o SRC e argumentos DEST. Note que você pode querer colocar aspas em torno $ SRC e US $ DEST no caso de conter espaços. Nós paramos looping quando SRC é o mesmo que DEST porque isso significa que nós batemos o argumento final (o destino).

Respondeu 05/11/2008 em 17:44
fonte usuário

votos
0

Você está correndo

./test.sh /home/dev/Examples/*.pdf /ankit_test/as 

e seu shell interativo está expandindo o curinga antes do script recebe-lo. Você só precisa citar o primeiro argumento quando você iniciá-lo, como em

./test.sh "/home/dev/Examples/*.pdf" /ankit_test/as

e depois, no seu script, citações "$ SRC" em qualquer lugar onde você literalmente quer as coisas com curingas (isto é, quando você faz echo $SRC, em vez usar echo "$SRC") e deixá-lo sem aspas quando você quer os wildcards expandidas. Basicamente, sempre colocar aspas em torno de coisas que possam conter metacaracteres shell menos que você queira os metacaracteres interpretados. :)

Respondeu 15/04/2012 em 14:08
fonte usuário

votos
1

Para vários arquivos de entrada usando um curinga, como * .txt, eu achei que isso funcione perfeitamente, não escape exigido. Ele deve funcionar apenas como um aplicativo nativo do bash como "ls" ou "rm". Este não foi documentado em qualquer lugar assim desde que eu passei a maior parte de 3 dias tentando descobrir isso eu decidi que deveria postá-lo para futuros leitores.

Diretório contém os seguintes arquivos (saída de ls)

file1.txt file2.txt file3.txt

Executar script como

$ ./script.sh *.txt

Ou mesmo como

$ ./script.sh file{1..3}.txt

o script

#!/bin/bash

# store default IFS, we need to temporarily change this
sfi=$IFS

#set IFS to $'\n\' - new line
IFS=$'\n'

if [[ -z $@ ]]
  then
  echo "Error: Missing required argument"
  echo
  exit 1
fi

# Put the file glob into an array
file=("$@")

# Now loop through them
for (( i=0 ; i < ${#file[*]} ; i++ ));
do

  if [ -w ${file[$i]} ]; then
     echo ${file[$i]} "  writable" 
  else
     echo ${file[$i]} " NOT writable"
  fi
done

# Reset IFS to its default value
IFS=$sfi

A saída

file1.txt writable
file2.txt writable
file3.txt writable

A chave estava mudando os IFS (Internal campo separador) temporariamente. Você tem que ter a certeza de armazenar esta antes de mudar e, em seguida, ligá-lo de volta quando você é feito com ele como demonstrado acima.

Agora você tem uma lista de arquivos expandidos ( com espaços escapou ) na matriz arquivo [] que você pode então percorrer. Eu gosto desta solução melhor, mais fácil de programar para e mais fácil para os usuários.

Respondeu 02/08/2012 em 14:29
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more