Iniciando um script externo com o comando source

5

Estou aprendendo scripts de shell, lendo bons tutoriais e lendo scripts.

Eu estava lendo este script de inicialização do minecraft , e essas primeiras linhas me atingiram:

if [ -L $0 ]
then
    source 'readlink -e $0 | sed "s:[^/]*$:config:"'
else
    source 'echo $0 | sed "s:[^/]*$:config:"'
fi

Portanto, essas linhas iniciam o script chamado "config" (onde todos os valores de configuração são armazenados) no mesmo shell. Mas por que, ao invés de lançar diretamente o arquivo (com algo como "source config", o autor desse script lê o nome do script original (se é um link ou não) e envia o resultado para sed para substituir este nome com "config"?

    
por Harkonnen 05.09.2013 / 11:30

2 respostas

4

Usando a fonte

O comando source não executa outro script. Simplesmente puxa o conteúdo deste outro script para este script e, em seguida, executa seu conteúdo como se fosse originalmente parte do script de chamada.

É basicamente um mecanismo para incluir o conteúdo de outro script no mesmo escopo que o seu.

Usando o readlink

Este comando está lá, caso o script original tenha sido chamado por meio de um link.

Usando sed

Este script está usando o sed para transformar o nome do script de chamada no nome config .

Exemplo

Digamos que tenhamos esse script chamado orig.bash :

#!/bin/bash

printf "exectued as:  %s\n" $0
cmd=$(readlink -e $0 | sed "s:[^/]*$:config:")
printf "sourcing as:  %s\n" "$cmd"

Este programa fará duas coisas.

  1. imprima o valor de $0

    printf "exectued as:  %s\n" $0
    
  2. imprima o valor do comando readlink ...

    cmd=$(readlink -e $0 | sed "s:[^/]*$:config:")
    printf "sourcing as:  %s\n" "$cmd"
    

Agora vamos criar um link para esse script, link2orig.bash . Portanto, temos os seguintes arquivos agora em nosso diretório:

# creates link
$ ln -s orig.bash link2orig.bash

# results after
$ ls -l
total 4
lrwxrwxrwx 1 saml saml   9 Sep  5 06:23 link2orig.bash -> orig.bash
-rwxrwxr-x 1 saml saml 126 Sep  5 06:31 orig.bash

Agora observe o que acontece

Então, agora, quando executamos nosso script de exemplo usando o nome real ou o link, ainda podemos substituir a coluna config pelo argumento do chamador. Qual é outro arquivo que contém informações de configuração para nosso script, que estamos pesquisando.

$ ./orig.bash 
executed as:  ./orig.bash
sourcing as:  /home/saml/tst/89518/config

$ ./link2orig.bash 
executed as:  ./link2orig.bash
sourcing as:  /home/saml/tst/89518/config

Se você perceber, uma das vantagens dessa abordagem é que ela é extremamente tolerante em ser chamada de diferentes maneiras e de diferentes locais no sistema.

$ ../89518/orig.bash 
executed as:  ../89518/orig.bash
sourcing as:  /home/saml/tst/89518/config

$ ../89518/link2orig.bash 
executed as:  ../89518/link2orig.bash
sourcing as:  /home/saml/tst/89518/config
    
por 05.09.2013 / 12:37
2

$0 é o caminho para o script. Normalmente, é o caminho completo para o script (ou seja, um caminho absoluto, começando com / ). No caso comum em que o script é executável e começa com uma linha shebang, o caminho será o caminho completo. Se o shell foi chamado explicitamente, no entanto, $0 é o que o usuário digitou na linha de comando, o que pode não incluir um caminho (com cd somedir; bash minecraft , $0 is minecraft ). Se o shell for invocado com o script na entrada padrão, $0 será o nome ou caminho do shell (com bash <minecraft , $0 is bash ).

Se o script for acessado por meio de um link simbólico, o script recuperará o caminho completo para esse link com todos os links simbólicos expandidos por meio do utilitário readlink específico do Linux.

A transformação no nome substitui o nome base do script por config . Ou seja, se $0 (ou readlink $0 , conforme o caso) for /path/to/minecraft , o comando sed gerará /path/to/config . Ele funciona mesmo se o caminho não contiver / : minecraft é substituído por config .

O objetivo desse script é procurar um arquivo chamado config no mesmo diretório do script e fonte (isto é, ler e executar esse script no mesmo contexto do script de chamada). config é um arquivo de configuração que serve para definir variáveis que são usadas posteriormente pelo script minecraft .

O script está sem aspas duplas em torno das substituições de variáveis e comandos . Deve ser escrito

if [ -L "$0" ]
then
    source "$(readlink -e "$0" | sed 's:[^/]*$:config:')"
else
    source "$(echo "$0" | sed 's:[^/]*$:config:')"
fi

Isso ainda falhará se o caminho para o script existir com - ou contiver uma nova linha, mas esses são casos raros.

A mesma ideia poderia ser escrita com construções de manipulação de string de shell (exceto para a chamada externa para readlink ).

case $0 in */*) config=$0;; *) config=./$0;; esac  # make sure there is a / in $config
if [ -L "$config" ]; then config=$(readlink -e -- "$config"); fi
config=${config%/*}/config
    
por 06.09.2013 / 02:44