No Bash, quando alias, quando script e quando escrever uma função?

339

Demorei quase 10 anos de uso do Linux para fazer essa pergunta. Foi tudo tentativa e erro e aleatória navegação na internet tarde da noite.

Mas as pessoas não precisam de 10 anos para isso. Se eu estivesse apenas começando com o Linux, eu gostaria de saber: Quando alias, quando escrever e quando escrever uma função?

Onde aliases estão em causa, eu uso aliases para operações muito simples que não aceitam argumentos.

alias houston='cd /home/username/.scripts/'

Isso parece óbvio. Mas algumas pessoas fazem isso:

alias command="bash bashscriptname"

(e adicione-o ao arquivo .bashrc )

Existe uma boa razão para fazer isso? Estou me esforçando muito, mas realmente não consigo pensar em nenhuma circunstância em que gostaria de fazer isso. Portanto, se houver um caso extremo em que isso possa fazer a diferença, responda abaixo.

Porque é onde eu colocaria algo no meu PATH e chmod +x , que é outra coisa que veio depois de anos de tentativa e erro do Linux.

O que me leva ao próximo tópico. Por exemplo, eu adicionei uma pasta oculta ( .scripts/ ) no diretório inicial ao meu PATH apenas adicionando uma linha ao meu .bashrc ( PATH=$PATH:/home/username/.scripts/ ), então qualquer coisa executável lá automaticamente auto-preenchida.

Se eu precisasse.

Eu realmente não preciso disso, embora? Eu só usaria isso para idiomas que não são o shell, como o Python.

Se for o shell, posso escrever apenas uma função dentro do mesmo .bashrc :

funcname () {
  somecommand -someARGS "$@"
}

Como afirmei, descobri muito disso por tentativa e erro. E eu só realmente vi a beleza das funções quando meu computador morreu e fui forçado a usar os computadores das pessoas ao meu redor quando eles não estavam usando.

Em vez de mover um diretório inteiro de scripts de computador para computador, acabei substituindo o .bashrc de todos os outros pelos meus, já que eles nunca tinham feito uma única modificação.

Mas eu senti falta de alguma coisa?

Então, o que você diria a um usuário iniciante sobre quando alias, quando escrever e quando escrever uma função?

Se não for óbvio, estou assumindo que as pessoas que responderem usarão as três opções. Se você usar somente aliases, ou apenas usar scripts, ou usar apenas funções— ou se você usar apenas aliases e scripts ou aliases e funções ou scripts e funções —esta pergunta não é realmente destinada a você.

    
por ixtmixilix 05.02.2012 / 14:12

14 respostas

229

Um alias não deve efetivamente (em geral) fazer mais do que alterar as opções padrão de um comando. Não é nada mais que simples substituição de texto no nome do comando. Não pode fazer nada com argumentos, mas passá-los para o comando que ele realmente executa. Então, se você simplesmente precisar adicionar um argumento na frente de um único comando, um alias funcionará. Exemplos comuns são

# Make ls output in color by default.
alias ls="ls --color=auto"
# make mv ask before overwriting a file by default
alias mv="mv -i"

Uma função deve ser usada quando você precisa fazer algo mais complexo do que um alias, mas isso não seria útil por si só. Por exemplo, responda a esta resposta em uma pergunta que fiz sobre a alteração do comportamento padrão de grep , dependendo de como é em um pipeline:

grep() { 
    if [[ -t 1 ]]; then 
        command grep -n "$@"
    else 
        command grep "$@"
    fi
}

É um exemplo perfeito de uma função porque é muito complexa para um alias (exigindo padrões diferentes com base em uma condição), mas não é algo que você precisará em um script não interativo.

Se você obtiver muitas funções ou funções muito grandes, coloque-as em arquivos separados em um diretório oculto e as atribua em ~/.bashrc :

if [ -d ~/.bash_functions ]; then
    for file in ~/.bash_functions/*; do
        . "$file"
    done
fi

Um script deve ficar por conta própria. Deve ter valor como algo que pode ser reutilizado ou usado para mais de um propósito.

    
por 05.02.2012 / 20:00
241

As outras respostas fornecem algumas orientações gerais suaves com base no gosto pessoal, mas ignoram muitos fatos pertinentes que devem ser considerados ao decidir entre scripts, funções ou aliases.

Aliases e Funções ¹

  • Todo o conteúdo dos aliases e funções é armazenado na memória do shell.
  • Uma conseqüência natural disso é que aliases e funções podem ser usadas apenas pelo shell atual, e não por outros programas que você possa invocar do shell, como editores de texto, scripts ou até instâncias filho. da mesma concha.
  • Os aliases e funções são executados pelo shell atual, ou seja, são executados e afetam o ambiente atual do shell.² Não é necessário nenhum processo separado para executar um alias ou uma função.

Scripts

  • Os shells não mantêm scripts na memória. Em vez disso, os scripts são lidos dos arquivos em que são armazenados sempre que são necessários. Se o script for encontrado por meio de uma pesquisa $PATH , muitos shells armazenam um hash do nome do caminho na memória para economizar tempo nas futuras verificações $PATH , mas essa é a extensão da memória de um script quando não está em uso.
  • Os scripts podem ser invocados de várias maneiras que funções e aliases podem. Eles podem ser passados como um argumento para um interpretador, como sh script , ou invocado diretamente como um executável, caso em que o interpretador na linha shebang (por exemplo, #!/bin/sh ) é invocado para executá-lo. Em ambos os casos, o script é executado por um processo de intérprete separado, com seu próprio ambiente separado do seu shell, cujo ambiente o script não pode afetar de forma alguma. De fato, o shell do interpretador não precisa nem corresponder ao shell invocador. Como os scripts invocados dessa maneira parecem se comportar como qualquer executável comum, eles podem ser usados por qualquer programa.

    Finalmente, um script pode ser lido e executado pelo shell atual com . , ou em alguns shells, source . Nesse caso, o script se comporta de maneira semelhante a uma função que é lida sob demanda, em vez de ser constantemente mantida na memória.

Aplicativo

Diante do exposto, podemos sugerir algumas diretrizes gerais para criar um script ou função / alias.

  • Outros programas além do seu shell precisam ser capazes de usá-lo? Em caso afirmativo, ele deve ser um script.

  • Você só quer que ele esteja disponível a partir de um shell interativo? É comum querer alterar o comportamento padrão de muitos comandos ao executar interativamente sem afetar comandos / scripts externos. Para este caso, use um alias / conjunto de funções no arquivo rc do "modo interativo" do shell (para bash this é .bashrc ).

  • Precisa alterar o ambiente do shell? Uma função / alias ou um script de origem são escolhas possíveis.

  • É algo que você usa com frequência? É provavelmente mais eficiente mantê-lo na memória, portanto, torne-o uma função / alias, se possível.

  • Por outro lado, é algo que você usa raramente? Nesse caso, não faz sentido tê-lo na memória quando você não precisa, então faça um script.

¹ Embora as funções e os aliases tenham algumas diferenças importantes, eles são agrupados porque as funções podem fazer tudo o que os aliases podem. Os aliases não podem ter variáveis locais nem podem processar argumentos e são inconvenientes para qualquer coisa mais longa que uma linha.

² Todo processo de execução em um sistema Unix tem um ambiente consistindo em um monte de variable=value pares que geralmente contêm configurações globais, como LANG para o local padrão e PATH para especificar o caminho de pesquisa executável.

    
por 05.02.2012 / 22:49
34

Acho que depende do gosto de cada pessoa. Para mim, a lógica é assim:

  • Primeiro, tento criar um alias, porque é o mais simples.
  • Se a coisa é muito complicada para caber em uma linha, eu tento fazer disso uma função.
  • Quando a função começa a crescer além de uma dúzia de linhas, eu a coloco em um script.

Não há nada que o impeça de fazer algo que funcione .

    
por 05.02.2012 / 15:52
14

Pelo menos parcialmente, é uma questão de gosto pessoal. Por outro lado, existem algumas distinções funcionais claras:

  • aliases: adequado apenas para substituições de texto simples, sem argumentos / parâmetros
  • funções: fácil de escrever / usar, capacidade de script de shell completo, disponível apenas dentro do bash
  • scripts: mais ou menos como funções, mas disponíveis (chamadas) fora do bash

Olhando para scripts de shell que fiz nos últimos anos, parei mais ou menos de escrever aliases (porque todos tendem a crescer em funções ao longo do tempo) e faço scripts apenas se precisarem estar disponíveis também de não-bash ambientes.

PS: Quanto a alias command="bash bashscriptname" , não vejo motivo para isso. Mesmo se bashscriptname não estiver em $ PATH, um simples alias c=/path/to/script seria suficiente.

    
por 05.02.2012 / 16:08
9

Quando escrever um script ...

  • Os scripts montam componentes de software (também conhecidos como ferramentas, comandos, processos, executáveis, programas) em componentes mais complexos, que podem ser montados em componentes ainda mais complexos.
  • Os scripts geralmente são executáveis para serem chamados pelo nome. Quando chamado, um novo subprocesso é gerado para o script ser executado. Cópias de qualquer export ed variáveis e / ou funções são passadas por valor para o script. As alterações nessas variáveis não são propagadas de volta para o script pai.
  • Os scripts também podem ser carregados (originados) como se fossem parte do script de chamada. Isso é análogo ao que outras linguagens chamam de "importar" ou "incluir". Quando originados, eles executam dentro do processo existente. Nenhum subprocesso é gerado.

Quando escrever uma função ...

  • Funções são scripts de shell efetivamente pré-carregados. Eles executam um pouco melhor do que chamar um script separado, mas somente se ele precisar ser lido no disco mecânico. A atual proliferação de flashdrives, SSDs e cache normal do Linux em RAM não utilizada faz com que a melhoria seja imensurável.
  • As funções servem como o principal meio de bash de obter modularidade, encapsulamento e reutilização. Eles melhoram a clareza, confiabilidade e capacidade de manutenção dos scripts.
  • As regras de sintaxe para chamar uma função são idênticas àquelas de chamar um executável. Uma função com o mesmo nome de um executável seria chamada em vez do executável.
  • As funções são locais para o script em que estão.
  • As funções podem ser exportadas ( copiadas por valor ) para que possam ser usadas dentro de scripts chamados. Assim, as funções só se propagam para processos filhos, nunca para pais.
  • As funções criam comandos reutilizáveis que geralmente são montados em bibliotecas (um script com apenas definições de função) para serem originados por outros scripts.

Quando escrever um alias ...

Dentro de scripts como scripts de biblioteca, às vezes é necessário um alias para uma função, como quando uma função é renomeada, mas a compatibilidade com versões anteriores é necessária. Isso pode ser feito criando uma função simples com o nome antigo que passa todos os seus argumentos para o nova função ...

# A bash in-script 'alias'
function oldFunction () { newFunction "$@"; }
    
por 06.02.2014 / 12:29
8

Uma outra coisa que não acredito ter sido levantada: uma função é executada no contexto do processo de chamada, enquanto um script bifurca um novo shell.

Isso pode ser importante para o desempenho - uma função é mais rápida, pois não é fork() e exec() . Em circunstâncias normais, a diferença é trivial, mas se você estiver depurando um sistema que está sem memória e que está debilitando a página, isso pode fazer uma grande diferença.

Além disso, se você quiser modificar seu ambiente shell atual, deverá usar uma função. Por exemplo, uma função poderia alterar a consulta de comando $PATH para o shell atual, mas um script não pode, porque ele opera em uma cópia fork / exec de $PATH .

    
por 08.02.2012 / 20:22
6

Script e alias e script e função não são mutuamente exclusivos. Você pode e armazena aliases e funções em scripts.

Scripts são apenas códigos que são persistentes . Funções úteis e aliases que você gosta de usar no futuro são armazenados em scripts. No entanto, um script é geralmente uma coleção de mais de uma função.

Como os aliases não são parametrizados , eles são muito limitados; geralmente para definir alguns parâmetros padrão.

Uma função é uma unidade separada de código , um conceito bem definido de algumas linhas de código que não podem ser separadas em partes menores e úteis; um que pode ser reutilizado diretamente ou outro por outras funções.

    
por 06.02.2012 / 11:26
5

Aqui estão alguns pontos adicionais sobre aliases e funções:

  • O alias e a função Same-named podem coexistir
  • O namespace de alias
  • é pesquisado primeiro (veja o primeiro exemplo)
  • aliases não podem ser (un) definidos em subshells ou ambientes não interativos (veja o segundo exemplo)

Por exemplo:

alias f='echo Alias'; f             # prints "Alias"
function f { echo 'Function'; }; f  # prints "Alias"
unalias f; f                        # prints "Function"

Como podemos ver, existem namespaces separados para aliases e funções; mais detalhes podem ser encontrados usando declare -A -p BASH_ALIASES e declare -f f , que imprime suas definições (ambas são armazenadas na memória).

Exemplo mostrando as limitações dos aliases:

alias a='echo Alias'
a        # OK: prints "Alias"
eval a;  # OK: prints "Alias"
( alias a="Nested"; a );  # prints "Alias" (not "Nested")
( unalias a; a );         # prints "Alias"
bash -c "alias aa='Another Alias'; aa"  # ERROR: bash: aa: command not found

Como podemos ver aliases não são aninhados, ao contrário de funções. Além disso, seu uso é limitado às sessões interativas.

Finalmente, note que você pode ter computação arbitrária em um alias declarando uma função imediatamente chamando-a, assim:

alias a_complex_thing='f() { do_stuff_in_function; } f'

que já está em uso generalizado no caso de aliases do Git. O benefício de fazer isso ao declarar uma função é que o seu alias não pode ser simplesmente sobrescrito pela origem (ou usando . ) de um script que declara uma função com o mesmo nome.

    
por 03.10.2015 / 22:25
4

Se for muito rápido, crie um alias ou uma função.

Se ele puder ser usado fora do seu shell preferido, crie um script. 1

Se receber argumentos, faça uma função ou um script.

Se precisar conter caracteres especiais, crie um alias ou um script. 2

Se precisar trabalhar com o sudo, crie um alias ou um script. 3

Se você quiser alterá-lo facilmente sem sair e entrar, um script é mais fácil. 4

Notas de rodapé

1 Ou crie um alias, coloque-o em ~/.env e defina export ENV="$HOME/.env" , mas é complicado fazê-lo funcionar portavelmente.

2 Os nomes de função devem ser identificadores, portanto, eles devem começar com uma letra e podem conter apenas letras, dígitos e sublinhados. Por exemplo, eu tenho um alias alias +='pushd +1' . Não pode ser uma função.

3 e adicione o alias alias sudo='sudo ' . Ditto qualquer outro comando, como strace , gdb , etc., que recebe um comando como seu primeiro argumento.

4 Veja também: fpath. Claro que você também pode fazer source ~/.bashrc ou similar, mas isso geralmente tem outros efeitos colaterais.

    
por 09.05.2012 / 17:44
3

Apenas para adicionar algumas notas:

  • Apenas script separado pode ser usado com o sudo (como se você precisar editar um arquivo de sistema), por exemplo:
sudo v /etc/rc.conf  #where v runs vim in a new terminal window;
  • Somente aliases ou funções podem substituir os comandos do sistema com o mesmo nome (supondo que você inclua o diretório de scripts no final do PATH, que é aconselhável para segurança em caso de criação acidental ou mal-intencionada de script com nome idêntico a um sistema comando), por exemplo:
alias ls='ls --color=auto'  #enable colored output;
  • Aliases e funções levam menos memória e tempo para execução, mas demoram para carregar (já que o shell precisa interpretar todos eles antes de mostrar o prompt). Leve isso em consideração se você executar novos processos shell regularmente, por exemplo:
# pressing key to open new terminal
# waiting for a few seconds before shell prompt finally appears.

Além disso, você pode usar a forma mais simples possível, ou seja, primeiro considerar o alias, depois a função e, em seguida, o script.

    
por 10.02.2012 / 17:37
2

Minha regra é:

  • aliases - um comando, sem parâmetros
  • funções - um comando alguns parâmetros
  • script - vários comandos, sem parâmetros
por 10.12.2015 / 03:00
1

Em um ambiente multiusuário (ou multi-sysamin), eu uso scripts para tudo, mesmo que acabe sendo apenas um curto 'exec something ....' wrapper.

Claro, é tecnicamente mais lento / menos eficiente que um alias ou uma função, mas isso quase nunca importa - e desde que esteja no caminho, um script sempre funciona.

Seu recurso pode ser chamado de cron, de algo com um ambiente reduzido ou modificado como sudo ou env, ou o usuário pode estar usando apenas um shell diferente para você - todos ou que provavelmente quebrará um alias ou uma função.

Se você tem algo sensível ao desempenho, lide com isso como um caso especial ou, melhor ainda, considere um gatilho para reescrever uma linguagem de script mais funcional.

Se estamos falando de recursos que serão usados apenas em outros scripts, você também pode considerar definir um shell padrão e escrever um script de biblioteca de funções que pode ser apenas. Dei origem a todos os outros scripts.

T

    
por 06.01.2016 / 19:39
0

Um exemplo para uma situação em que você provavelmente gostaria de usar um alias.

Eu sei que este é um post antigo, mas gostaria de apontar uma situação em que quase precisei usar uma combinação de alias com um script e optei por não usar uma função.

Eu tenho um script em ~/.bin/ chamado setup que faz o seguinte: 1

  1. me leva a um determinado diretório.
  2. define algumas variáveis.
  3. imprime mensagens sobre o estado do diretório. 2

O ponto é que se eu executasse apenas setup <project-name> eu não teria essas variáveis definidas e não teria chegado ao diretório. A solução que achei melhor foi adicionar esse script a PATH e adicionar alias setup=". ~/.bin/setup" a ~/.bashrc ou qualquer outra coisa.

Notas:

  1. Eu usei um script para essa tarefa e não uma função, não porque seja particularmente longa, mas porque posso editá-la e não preciso fornecer o arquivo após uma edição, se quiser atualizá-lo.
  2. Um caso semelhante me foi acertado quando criei um script para recarregar todos os meus dotfiles. 3
  1. The script is available in my dotfiles repository under .bin/.
  2. About the script: I give this script an argument which is a name for the project I defined in advanced. Afterwards the script knows to bring to me to the right directory according to a certain csv file. The variables it defines are taken from the makefile in that directory. The script runs afterwards ls -l and git status to show me what's going on there.
  3. That script is also available in my dotfiles repository under .bin/ as well.
    
por 25.04.2016 / 21:32
-8
  1. alias para substituição de texto de linha única
  2. scripts para mais nada.
por 06.02.2012 / 06:16