Eu tenho uma função bash para definir o $PATH
seguinte -
assign-path()
{
str=$1
# if the $PATH is empty, assign it directly.
if [ -z $PATH ]; then
PATH=$str;
# if the $PATH does not contain the substring, append it with ':'.
elif [[ $PATH != *$str* ]]; then
PATH=$PATH:$str;
fi
}
Mas o problema é que tenho que escrever funções diferentes para variáveis diferentes (por exemplo, outra função para $CLASSPATH
curtir assign-classpath()
etc.). Não consegui encontrar uma maneira de passar o argumento para a função bash para que eu possa acessá-lo por referência.
Seria melhor se eu tivesse algo como -
assign( bigstr, substr )
{
if [ -z bigstr ]; then
bigstr=substr;
elif [[ bigstr != *str* ]]; then
bigstr=bigstr:substr;
fi
}
Alguma idéia, como conseguir algo como o acima no bash?
bash
bash-script
ramgorur
fonte
fonte
assign-path /abc
não irá acrescentar/abc
ao PATH se $ PATH já contém/abc/def
,/abcd
,/def/abc
etc. Especialmente você não pode adicionar/bin
se PATH já contém/usr/bin
.$PATH
e teste negate contra seus argumentos como:add=/bin dir=/usr/bin ; [ -z "${dir%"$add"}" ] || dir="${dir}:${add}"
. Na minha resposta, eu faço dessa maneira com quantos argumentos você quiser usar apenasIFS=:
.$PATH
? e Adicionar diretório para$PATH
se ele ainda não estiver lá (no Superusuário ).Respostas:
Em
bash
você pode usar${!varname}
para expandir a variável referenciada pelo conteúdo de outra. Por exemplo:Na página do manual:
Além disso, para definir uma variável referenciada pelo conteúdo (sem os perigos de
eval
), você pode usardeclare
. Por exemplo:Assim, você pode escrever sua função assim (tome cuidado, porque se você usar
declare
uma função, deverá fornecer-g
ou a variável será local):E use-o como:
Observe que também corrigi um erro em que, se
substr
já é uma substring de um dos membros separados por dois pontos debigstr
, mas não seu próprio membro, ele não seria adicionado. Por exemplo, isso permitiria adicionar/bin
a umaPATH
variável que já contém/usr/bin
. Ele usa osextglob
conjuntos para coincidir com o início / fim da string ou com dois pontos e depois com qualquer outra coisa. Semextglob
, a alternativa seria:fonte
-g
indeclare
não está disponível na versão mais antiga do bash, existe alguma maneira para que eu possa tornar isso compatível com versões anteriores?export
colocá-lo em seu ambiente (com o risco de sobrescrever algo importante) oueval
(vários problemas, incluindo segurança, se você não tomar cuidado). Se estiver usando,eval
você deve estar bem, se quisereval "$target=\$substr"
. Se você esquecer o\
que é, ele potencialmente executará um comando se houver um espaço no conteúdo desubstr
.Novo no bash 4.3, é a
-n
opção paradeclare
&local
:Isso é impresso
hello, world
.fonte
Você pode usar
eval
para definir um parâmetro. Uma descrição deste comando pode ser encontrada aqui . O seguinte uso deeval
está errado:Com relação à avaliação adicional,
eval
você deve usarVerifique os resultados do uso destas funções:
Mas você pode alcançar seu objetivo sem o uso de
eval
. Eu prefiro esse caminho que é mais simples.A função a seguir faz a substituição da maneira correta (espero)
Verifique a seguinte saída
Agora você pode usar a
augment
função da seguinte maneira para definir uma variável:fonte
v='echo "OHNO!" ; var' ; l=val ; eval $v='$l'
- ecoaria "OHNO! Antes de atribuir var. Você poderia" $ {v ## * [; "$ IFS"]} = '$ l' "para garantir que a cadeia não possa se expandir para algo que não será avaliado com o =.=
instrução de atribuição. Você pode argumentar que meu script não verifica seu argumento. Isso é verdade. Nem checo se existe algum argumento ou se o número de argumentos é válido. Mas isso foi por intenção. O OP pode adicionar essas verificações, se ele quiser.v
(melhor seu valor) como segundo argumento da função de atribuição. Portanto, seu valor deve estar no lado direito de uma tarefa. É necessário citar o argumento da funçãoassign
. Eu adicionei essa sutileza à minha postagem.Com alguns truques, você pode realmente passar parâmetros nomeados para funções, juntamente com matrizes (testadas nos bash 3 e 4).
O método que eu desenvolvi permite acessar parâmetros passados para uma função como esta:
Em outras palavras, não apenas você pode chamar seus parâmetros pelos nomes (o que compõe um núcleo mais legível), como também pode passar matrizes (e referências a variáveis - esse recurso funciona apenas no bash 4.3)! Além disso, as variáveis mapeadas estão todas no escopo local, assim como $ 1 (e outras).
O código que faz esse trabalho é bastante leve e funciona tanto no bash 3 quanto no bash 4 (essas são as únicas versões com as quais eu testei). Se você estiver interessado em mais truques como esse que tornam o desenvolvimento com o bash muito mais agradável e fácil, você pode dar uma olhada no meu Bash Infinity Framework , o código abaixo foi desenvolvido para esse fim.
fonte
Isso se encaixa?
fonte
eval
é suscetível à execução arbitrária de comandos.eval
linhas zhe mais seguras? Normalmente, quando acho que preciso avaliar, decido não usar * sh e mudar para um idioma diferente. Por outro lado, usando isso em scrips anexar entradas para alguns PATH-like variáveis, ele será executado com constantes de cadeia e não a entrada do usuário ...eval
com segurança - mas é preciso muito pensamento. Se você está apenas tentando fazer referência a um parâmetro, gostaria de fazer algo assim:eval "$1=\"\$2\""
dessa maneira, naeval's
primeira passagem, ele avalia apenas $ 1 e, no segundo, valor = "$ 2". Mas você precisa fazer outra coisa - isso é desnecessário aqui."${1##*[;"$IFS"]}=\"\$2\""
- e mesmo isso vem sem garantia. Oreval "$(set -- $1 ; shift $(($#-1)) ; echo $1)=\"\$2\""
. Não é fácil.Argumentos nomeados simplesmente não são como a sintaxe de Bash foi projetada. O Bash foi projetado para ser uma melhoria iterativa do shell Bourne. Como tal, ele deve garantir que certas coisas funcionem entre as duas conchas o máximo possível. Portanto, não é destinado para ser mais fácil de script com No geral, é apenas pretende ser melhor do que Bourne, assegurando que se você tomar um script a partir de um ambiente de Bourne sobre a
bash
é tão fácil quanto possível. Isso não é trivial, pois muitas conchas ainda tratam Bourne como um padrão de fato. Como as pessoas escrevem seus scripts para serem compatíveis com Bourne (para essa portabilidade), a necessidade permanece em vigor e é improvável que alguma vez mude.Você provavelmente está melhor vendo um shell script diferente (como
python
algo assim) inteiramente, se for possível. Se você estiver enfrentando as limitações de um idioma, precisará começar a usar um novo idioma.fonte
bash
vida isso fosse verdade. Mas agora são tomadas disposições específicas. Variáveis de referência completas agora estão disponíveis embash 4.3
- veja a resposta de derobert .Com a
sh
sintaxe padrão (funcionariabash
, e não apenasbash
), você poderia:Como por soluções usando
bash
'sdeclare
, é seguro , desde que$1
contém um nome de variável válido.fonte
SOBRE ARGOS NOMEADOS:
Isso é feito com muita simplicidade e
bash
não é necessário - este é o comportamento básico especificado da atribuição do POSIX via expansão de parâmetro:Para fazer uma demonstração semelhante à @Graeme, mas de maneira portátil:
E só faço isso
str=
para garantir que ele tenha um valor nulo, porque a expansão de parâmetros tem a proteção interna contra a reatribuição do ambiente do shell em linha, se já estiver definido.SOLUÇÃO:
Para o seu problema específico, não acredito que os argumentos nomeados sejam necessários, embora certamente sejam possíveis. Use em
$IFS
vez disso:Aqui está o que recebo quando o executo:
Observe que apenas adicionou os argumentos que ainda não estavam presentes
$PATH
ou que vieram antes? Ou mesmo que foram necessários mais de um argumento?$IFS
é útil.fonte
assign
aqui. Se você tiver dúvidas sobre como funciona, ficarei feliz em responder. E, a propósito, se você realmente quiser argumentos nomeados, talvez queira examinar esta outra resposta minha, na qual mostro como declarar uma função nomeada para os argumentos de outra função: unix.stackexchange.com/a/120531/52934Não consigo encontrar nada como ruby, python, etc., mas isso parece mais próximo de mim
A legibilidade é melhor na minha opinião, 4 linhas são excessivas para declarar os nomes dos parâmetros. Parece mais próximo das línguas modernas também.
fonte
a=$1 b=$2 ...
funciona tão bem.