Problema com a entrada do script simples que copia um arquivo para um diretório diferente

4

Como alguém tentando aprender bash, tenho feito scripts simples para testar vários comandos. No seguinte script simples, estou experimentando o comando read.

#!/bin/bash
read -p "Enter a path to a file: " file_to_copy
cp $file_to_copy /tmp

Se o usuário inserir o caminho inteiro em um arquivo de teste, por exemplo, / home / $ USER / test quando solicitado, o script é executado como esperado e faz uma cópia de "test" no diretório / tmp. No entanto, se o usuário digitar o shorthand ~ / test, o terminal retornará o erro cp: não pode stat '~ / test': Nenhum arquivo ou diretório. Por que o comando cp não consegue encontrar uma representação equivalente? do caminho do arquivo quando entrou?

Se eu inserir de forma independente no terminal:

cp ~/test /tmp

o arquivo de teste é copiado sem incidentes, então é provavelmente uma nuança de atribuição de variáveis que eu errei, mas não consigo entender.

Obrigado.

    
por mike3759 21.12.2015 / 05:20

2 respostas

2

O que acontece é que você literalmente pede ao shell para encontrar ~/test do diretório em que o script está atualmente. Em outras palavras, se você executar a partir de /home/$USER , ele estará procurando pelo arquivo test no subdiretório ~ , não a expansão /home/$USER/test .

O que você pode usar é o eval construído em bash , que pegará todos os argumentos e os reunirá como um comando e deixará o shell executá-lo. Agora, o shell expandirá ~ .

xieerqi:
$ ./copyScript.sh                                                                                                       
Enter a path to a file: ~/test
Entered /home/xieerqi/test

xieerqi:
$ ls -l /tmp/test
-rw-rw-r-- 1 xieerqi xieerqi 0 Dec 21 01:14 /tmp/test

xieerqi:
$ cat copyScript.sh
#!/bin/bash

read -p "Enter a path to a file: " file_to_copy
file_to_copy=$(eval echo $file_to_copy)
echo "Entered $file_to_copy"
cp "$file_to_copy" /tmp

Sugiro que você também use aspas em torno da substituição de comando $( . . .) , para garantir que os arquivos com espaços neles e caracteres especiais sejam capturados adequadamente em file_to_copy variable

ADIÇÃO

Como afirmado nos comentários, eval integrado pode ser perigoso.

Pessoalmente, uso o comando readlink com bastante frequência em meus scripts e evito usar ~ . E como neste script você solicita a entrada do usuário, por que não usar argumentos de linha de comando? Assim:

xieerqi:
$ ./copyScript.sh testFile.txt                                
/home/xieerqi/testFile.txt

xieerqi:
$ cat copyScript.sh                                           
#!/bin/bash

FILE="$(readlink -f "$@" )"

echo $FILE
# uncomment for copying
# cp $FILE /tmp

dirname e basename

GNU coreutils fornece dois comandos, basename e dirname . basename mostra o último elemento no caminho e dirname mostra tudo que precede o último elemento. Pode-se usar a expansão de parâmetro interno de bash para fazer o mesmo, mas já que temos essas ferramentas - por que não usá-las:

xieerqi:
$ ./copyScript.sh                                             
Enter path to file: ~/testFile.txt
File entered is  /home/xieerqi/testFile.txt

xieerqi:
$ ./copyScript.sh                                             
Enter path to file: ~/sumFile.txt
File entered is  /home/xieerqi/sumFile.txt
ERROR, file doesn't exist

xieerqi:
$ cat copyScript.sh                                           
#!/bin/bash

read -p "Enter path to file: " FILEPATH

DIRPATH="$(dirname "$FILEPATH")"
FILENAME="$(basename "$FILEPATH" )"

if [ "$DIRPATH" == "~"   ];then
  DIRPATH="$HOME"
fi

FILEPATH="$DIRPATH"/"$FILENAME"
echo "File entered is " "$FILEPATH"

[ -e "$FILEPATH"  ] || { echo "ERROR, file doesn't exist"; exit 1;}
    
por Sergiy Kolodyazhnyy 21.12.2015 / 09:17
4

Experimente estes comandos no seu script:

#!/bin/bash
read -p "Enter a path to a file: " file_to_copy
file_to_copy=$(bash -c "echo $file_to_copy")
file_to_copy=${file_to_copy/~\//$HOME\/}
cp "${file_to_copy}" /tmp

Explicação:

  • A terceira linha expandirá os valores da variável env , se houver alguma presente.

  • A quarta linha do código acima tentará procurar por ~ na sua variável file_to_copy e, se encontrada, será substituída por $HOME caminho.

  • E \/ here \ é um caractere de seqüência de escape de barra invertida para / , pois queremos substituir ~/ por $HOME/ .

por snoop 21.12.2015 / 05:48