one-liner vs script


25

Eu notei muitas perguntas, respostas e comentários expressando desdém por (e às vezes até medo de) escrever scripts em vez de frases simples. Então, eu gostaria de saber:

  • Quando e por que devo escrever um script independente em vez de um "one-liner"? Ou vice-versa?

  • Quais são os casos de uso e os prós e contras de ambos?

  • Algumas linguagens (por exemplo, awk ou perl) são mais adequadas para one-liners do que outras (por exemplo, python)? Se sim, por quê?

  • É apenas uma questão de preferência pessoal ou existem boas razões (ou seja, objetivas) para escrever uma ou outra em circunstâncias particulares? Quais são esses motivos?

Definições

  • one-liner: qualquer sequência de comandos digitados ou colados diretamente em uma linha de comando do shell . Muitas vezes envolvendo oleodutos e / ou uso de linguagens como sed, awk, perl, e / ou ferramentas como grepou cutou sort.

    É a execução direta na linha de comando que é a característica definidora - o comprimento e a formatação são irrelevantes. Um "one-liner" pode estar todo em uma linha ou pode ter várias linhas (por exemplo, sh para loop ou código awk ou sed incorporado, com feeds de linha e recuo para melhorar a legibilidade).

  • script: qualquer sequência de comandos em qualquer idioma interpretado que é salvo em um arquivo e, em seguida, executado. Um script pode ser escrito inteiramente em um idioma ou pode ser um wrapper de script de shell em vários "one-liners" usando outros idiomas.


Eu tenho minha própria resposta (que postarei mais tarde), mas quero que isso se torne uma sessão de perguntas e respostas canônicas sobre o assunto, não apenas minha opinião pessoal.



4
Em relação ao Python, geralmente é ruim para as linhas únicas porque o espaço em branco faz parte da sintaxe, incluindo recuo e novas linhas . Além disso, é mais detalhado e explícito do que a maioria dos outros idiomas comuns.
wjandrea 30/09

2
Qualquer coisa que eu precisei pesquisar no Google (algumas regex, normalmente) e que possa ser reutilizada de alguma forma ou variante, salvarei em um arquivo de script na nuvem (dropbox, google cloud, qualquer que seja). O comentário contém as palavras-chave que eu sei que vou usar quando precisar novamente. Ele economiza mais de 5 minutos repensando minhas escolhas entre várias respostas semelhantes e evitando armadilhas ou construindo a variante necessária, pois não encontrei a variante exata e bem escrita de que precisava.
user3445853

3
@wjandrea Para adicionar: regexes. O Perl possui uma sintaxe específica para eles, que inclui a operação a ser executada etc. No python, você precisa de uma função de importação e gravação com strings literais como argumentos que exigem muito mais caracteres. A maioria das one-liners usa muitas expressões regulares para manipular o texto, então esse é um "grande problema".
Giacomo Alzetta

11
@wjandrea Python não é ruim para one-liners, não no sentido de não ser capaz de escrever um. Em média, eu fui capaz de transformar scripts de 4-5 linhas em one-liners. Mas, como você mencionou, é mais explícito do que outras linguagens (que IMHO é uma das vantagens do Python). Portanto, eles podem contar com o dobro ou o triplo de caracteres do que dizer Perl ou awk (que também não precisam importar algumas bibliotecas, diferentemente do Python), e é sobre isso que a maioria das pessoas reclama - o tamanho dessas falas. Mas, novamente, IMHO é mesquinho discutir sobre a contagem de caracteres; se algo funciona - funciona
Sergiy Kolodyazhnyy

Respostas:


33

Outra resposta baseada na experiência prática.

Eu usaria uma linha só se fosse um código "descartável" que eu pudesse escrever diretamente no prompt. Por exemplo, eu posso usar isso:

for h in host1 host2 host3; do printf "%s\t%s\n" "$h" "$(ssh "$h" uptime)"; done

Eu usaria um script se decidisse que valia a pena salvar o código. Nesse ponto, eu adicionaria uma descrição na parte superior do arquivo, provavelmente adicionaria alguma verificação de erro e talvez até a verificasse em um repositório de código para obter versões. Por exemplo, se eu decidisse que verificar o tempo de atividade de um conjunto de servidores era uma função útil que eu usaria repetidamente, o one-liner acima pode ser expandido para isso:

#!/bin/bash
# Check the uptime for each of the known set of hosts
########################################################################
#
hosts=(host1 host2 host3)

for h in "${hosts[@]}"
do
    printf "%s\t" "$h"
    uptime=$(ssh -o ConnectTimeout=5 -n "$h" uptime 2>/dev/null)
    printf "%s\n" "${uptime:-(unreachable)}"
done

Generalizando, pode-se dizer

  • One-liner

    • Código simples (ou seja, apenas "algumas" instruções), escritas para uma finalidade específica
    • Código que pode ser escrito de maneira rápida e fácil sempre que necessário
    • Código descartável
  • Roteiro

    • Código que (provavelmente) será usado mais de uma ou duas vezes
    • Código complexo que requer mais do que "algumas" instruções
    • Código que precisará ser mantido por terceiros
    • Código a ser entendido por outras pessoas
    • Código a ser executado autônomo (por exemplo, de cron)

Vejo um número razoável de perguntas aqui no unix.SE solicitando que uma única linha execute uma tarefa específica. Usando meus exemplos acima, acho que o segundo é muito mais compreensível que o primeiro e, portanto, os leitores podem aprender mais com ele. Uma solução pode ser facilmente derivada da outra, portanto, no interesse da legibilidade (para futuros leitores), provavelmente devemos evitar fornecer código compactado em uma linha para qualquer outra coisa que não seja a mais trivial das soluções.


Esse é um bom exemplo prático de como um one-liner rápido e sujo pode evoluir para um script mais robusto.
Anthony G - justice for Monica

Este é um bom começo, mas há outra possibilidade. Tenho algumas coisas úteis para usar mais de uma ou duas vezes, mas provavelmente não na mesma máquina. Eu os salvo em um arquivo de texto que eu mantenho aberto o tempo todo no meu computador de trabalho, para que eu possa copiá-los rapidamente e colá-los no meu cliente SSH (ou em um prompt de comando em um servidor Windows). Estes não são necessariamente "one liners", nem procuro salvá-los em arquivos como "scripts". Eu os chamo de "receitas".
Monty Harder

@MontyHarder Nesses casos, costumo salvá-los como scripts e depois armazená-los em um repositório git. Eu posso simplesmente instalá-los em qualquer máquina necessária através de um simples clone do git. Isso é para o trabalho. Para uso pessoal, nunca escrevo código em um arquivo "receita" (não uso trechos do github, por exemplo). Eu salvo todos os meus scripts em um diretório $ HOME / bin que eu guardo desde os meus dias de faculdade em 1997 (no SunOS das universidades). Eu tive a idéia do romance Neuromancer, onde tanto o protagonista quanto o antagonista mantinham scripts / programas pessoais para usar como armas
slebetman

11
Embora certamente é tangencial à discussão real, no seu exemplo script que você poderia usar set -- host1 host2 host3, em seguida, for h in "$@"(ou apenas for h), o que tornaria o script POSIX-portátil. :-)
wchargin

2
Gosto da questão de tornar o código mais legível para OP e para os espectadores aprenderem. Melhor talvez fazer as duas coisas em uma resposta, mas acho mais fácil concatenar um script do que desconstruir um liner pessoalmente.
FreeSoftwareServers

10

Escreva um script quando:

  • é necessário mais código
  • você valoriza a legibilidade
  • é necessário / útil adicionar comentários, mostrar o que o código faz
  • você precisa passar parâmetros
  • você deseja que o script seja executado em seu próprio ambiente (variáveis ​​etc.)
  • você provavelmente vai reutilizar / adaptar o código para fins mais complexos

Escreva uma linha quando:

  • apenas uma pequena quantidade de código é necessária
  • você deseja acessar variáveis ​​definidas no shell atual
  • você precisa de uma solução rápida e suja

Geralmente é fácil modificar em que coisas uma linha funciona. Esse ponto de "passagem de parâmetros" para um script talvez deva ser "você deseja empacotá-lo para uso simples posteriormente". Eu escrevi "one-liners" que incluem definir uma função shell e chamá-la. Embora agora que eu pense sobre isso, esse tenha se estabelecido após várias iterações e eu devo colocá-lo em um script.
Peter Cordes em

9

Quando uma série necessária de comandos é bastante curta e / ou produz um resultado que pode ser usado como parte de um pipeline maior ou de um alias de comando, pode ser uma boa opção.

Basicamente, acho que one-liners geralmente são coisas que um administrador de sistema experiente, familiarizado com o problema e com os comandos usados, pode escrever no local, sem pensar demais.

Quando um one-liner se torna excessivamente longo ou envolve mais do que condicionais ou loops muito simples, geralmente é melhor escrevê-los como um script de várias linhas ou função de shell, para facilitar a leitura. Além disso, se for algo que você escreve para ser usado repetidamente, ou algo que será usado (e possivelmente relacionado a problemas) por outras pessoas, você deve dedicar algum tempo para escrever a solução em um comentário mais claro, formulário de script.

No Python, a indentação faz parte da sintaxe; portanto, você literalmente não pode usar os recursos da linguagem em toda a extensão se escrever uma linha.

As linhas de comando perl e awk costumam usar o poder bruto das expressões regulares. Mas alguns chamam as expressões regulares de linguagem somente gravação, não inteiramente sem razão. Escrever um script de várias linhas permite escrever comentários para descrever o que uma expressão regular específica deve estar fazendo, o que será muito útil quando você olhar o script novamente, depois de fazer outras coisas por seis meses.

Essa é uma questão inerentemente muito baseada em opiniões, pois envolve a avaliação da quantidade de complexidade aceitável e as vantagens e desvantagens entre legibilidade e compacidade; tudo isso é muito questão de julgamento pessoal. Até a escolha de um idioma pode depender de assuntos pessoais: se um idioma em particular seria ideal para um problema em particular, mas você não o conhece e já sabe como resolver o problema com outro idioma, pode escolher a opção linguagem familiar para concluir o trabalho rapidamente e com o mínimo de esforço, embora a solução possa ser tecnicamente um pouco ineficiente.

O melhor é muitas vezes o inimigo do bom o suficiente , e isso se aplica muito aqui.

E se você conhece o Perl, já deve ter ouvido falar do TMTOWTDI: Há mais de uma maneira de fazer isso.


mais um por mencionar "ou função de shell"
glenn jackman

7

Por favor, note que esta é uma opinião pessoal; tomá-lo com um grão de sal.

  1. Se o comando se encaixar em, digamos, 80 caracteres, use uma linha. É difícil trabalhar com linhas de comando longas. Há também o problema da recorrência, veja # 2

  2. Se você precisar executar o (s) comando (s) mais de uma vez, use um script. Caso contrário, use uma linha, desde que a condição nº 1 seja atendida.

  3. Isso é muito subjetivo, mas sim, vejo shell, Perl ou awk como sendo minhas ferramentas essenciais para one-liners.
  4. Veja # 1, # 2, # 3.

3
Estou gostando das respostas que vi até agora. Gosto especialmente do seu primeiro ponto - editar é uma das coisas que planejava mencionar na minha resposta - mesmo com ^ X ^ E, é muito mais fácil e muito mais agradável editar um script no seu editor favorito do que editar no comando- linha.
cas

2
Votado embora o ponto 4 pareça meio inútil. :)
Anthony G - justice for Monica

@cas: com control-seta-chave (ou alt + f / alt + b) você pode se mover em um one-liner muito rápido. Especialmente se você tiver as principais configurações de repetição automática em 50 / s com um atraso de 220ms. Você também pode usar control-s / control-r isearch em uma única linha, embora isso possa levá-lo de volta a outro histórico. Se você é bom com control-w, alt + backspace, alt + de control-y, pode fazer muito com apenas o movimento do cursor do teclado.
Peter Cordes em

Além disso, algumas conchas do IIRC (como o ZSH, eu acho) têm um atalho de teclado para chamar um editor na linha de comando atual, permitindo que você componha um "one-liner" em seu editor favorito e inclua isso facilmente no histórico de comandos para obter mais atualizações. seta e edição. (Ser capaz de modificá-lo para reexecuções é o que torna os one-liners ótimos, em comparação com as opções de linha de comando em um script.) IIRC, o bash também possui edição externa, mas não está vinculado a nada por padrão.
Peter Cordes em

O @ PeterCordes, mover o cursor muito rápido, nem começa a se comparar com o que você pode fazer em um editor decente como o vi / vim. btw, ^ X ^ E chama $ EDITOR ou $ VISUAL no bash (e alguns outros shells. zsh também, eu acho. configurável). é uma boa maneira de transformar a bagunça ilegível que criei em algo compreensível, inserindo feeds de linha e recuo - é fácil se perder em chaves ou suportes aninhados sem elas. Aliás, minhas janelas de terminal têm mais de 250 caracteres de largura, de modo que minhas linhas de base podem ficar muito longas, mesmo sem quebra.
cas

7

Visualizo e uso um one-liner como uma ferramenta de desenvolvimento temporária para editar repetidamente até que faça o que eu quero, ou entendo como funciona uma sutileza de um subcomando.

Em seguida, ele é anotado (e anotado) em um arquivo de texto sobre o assunto que eu estava investigando ou limpo em um script que é colocado na minha caixa pessoal PATH, possivelmente para aperfeiçoamento, parametrização e assim por diante. Normalmente, a única linha será dividida em mais legível, mesmo que nenhuma outra alteração seja feita ou se eu nunca mais usar o script.

Defino meu histórico de shell para mais de 5000 linhas, com um histórico separado por terminal e por login em um controle remoto e assim por diante. Detesto não poder encontrar nessas histórias um comando de uma linha que desenvolvi há algumas semanas e não achei que fosse necessário novamente, daí a minha estratégia.

Às vezes, um grupo inteiro de comandos precisa fazer algo, como configurar algum hardware; no final, copio todos eles do histórico, limpo-os minimamente e os adiciono a um script de shell RUNMEapenas como notas sobre o que fiz, mas também para que estejam quase prontos para serem usados ​​novamente por outra pessoa. (É por isso que encontro ferramentas que fornecem apenas uma interface gráfica do usuário para configurá-las de tal maneira.) Acho isso um ganho incrível em eficiência, pois muitas vezes algo que você espera fazer apenas uma vez deve ser feito mais 5 vezes. .


11
Os one-liners +1 são ótimos para seta para cima e edição, em comparação à implementação de opções de linha de comando para um script para controlar o que ele faz separadamente do que ele opera. por exemplo, alteração lnvs. ln -slinks diretos vs. soft em uma linha que faz um loop em alguns arquivos.
Peter Cordes em

5

Eu gostaria que as pessoas da minha equipe escrevessem scripts para quaisquer operações que possam ser necessárias para serem executadas mais de uma vez (ou seja, "fluxos de trabalho" ou "pipelines") e para qualquer tarefa pontual que seja exigida para ser documentada (normalmente coisas como "modificar certas coisas em alguns conjuntos de dados para corrigir dados fornecidos incorretamente" (no nosso caso). Além disso, "one-liners" ou scripts não importam muito.

A falta de documentação adequada dos fluxos de trabalho (como scripts ou equivalente) dificulta a introdução de novas equipes em um projeto e também a transição das pessoas para fora de um projeto. Além disso, dificulta qualquer tipo de auditoria, e o rastreamento de erros pode ser impossível.

Isso independentemente da linguagem usada para a programação.

Outros locais de trabalho podem ter costumes ou expectativas semelhantes / diferentes, talvez até anotados.

Em casa, você faz o que quiser.

Por exemplo, escrevo scripts assim que faço algo não trivial no shell, como antes de enviar uma resposta a uma pergunta de U&L ou sempre que preciso testar os componentes individuais de um comando ou conjunto de comandos antes de executá-lo "para real".

Também escrevo scripts para tarefas repetitivas que realmente quero sempre da mesma maneira, mesmo que sejam simples, como

  • atualizar meu sistema OpenBSD e todos os pacotes instalados (isso se resume a três comandos curtos e vários outros para limpeza, coletados em um script curto), ou
  • fazer backup do meu sistema em um armazenamento externo (essencialmente um único comando, mas novamente com bastante limpeza e o script também me permite fazer diferenças entre os instantâneos etc., e ele precisa funcionar sutilmente diferente em diferentes sistemas, e Eu o executo de um trabalho cron) ou
  • buscando correio (novamente, essencialmente um único comando, mas quero que ele se comporte de maneira diferente quando chamado como um trabalho cron e quando eu o uso na linha de comando, e ele não deve tentar buscar correio sob algumas circunstâncias, e escreve um mensagem de log curta para um arquivo).

Uso funções de shell (raramente aliases) para conveniência em shells interativos, por exemplo, para adicionar opções a certos comandos por padrão ( -Fpara ls) ou para criar variações especializadas de alguns comandos ( pmanaqui está um mancomando que apenas analisa os manuais do POSIX, por exemplo) .


5

Parece que tenho uma opinião minoritária sobre isso.

O termo "script" é intencionalmente confuso, livre-se dele. Este é um software que você está escrevendo lá, mesmo se estiver usando apenas bashe awk.

Dentro de uma equipe, prefiro escrever software com o processo de revisão de código imposto por uma ferramenta (github / gitlab / gerrit). Isso fornece controle de versão como um bônus. Se você tiver vários sistemas, adicione ferramentas de implantação contínua. E alguns conjuntos de testes, se os sistemas de destino forem importantes. Eu não sou religioso sobre isso, mas peso os benefícios e custos.

Se você possui uma equipe de administradores, o mais simples vim /root/bin/x.shé principalmente um desastre em termos de comunicação relacionada à mudança, legibilidade do código e distribuição entre sistemas. Muitas vezes, um mau funcionamento sério custa mais tempo / dinheiro do que o processo supostamente "pesado".

I prefer one-liners , na verdade, para qualquer coisa que não merece esse processo "pesado". Eles podem ser reutilizados rapidamente, com algumas teclas, se você souber como usar seu histórico de shell com eficiência; colado facilmente entre sistemas não relacionados (por exemplo, clientes diferentes).

Diferença crucial entre os one-liners (não revisados!) E o software analisado ("scripts"): a responsabilidade é totalmente sua quando você executa os one-liners. Você nunca pode dizer para si mesmo "Acabei de encontrar essa linha em algum lugar, executei-a sem entender, o que se segue não é minha culpa" - você sabia que estava executando um software não revisado e não testado, por isso é sua culpa. Certifique-se de que seja pequeno o suficiente para que você possa prever os resultados - que se dane.

Às vezes, você precisa dessa abordagem simplista e definir a barra em cerca de uma linha de texto funciona bem na prática (ou seja, o limite entre o código revisado e o não revisado). Algumas de minhas falas parecem terrivelmente longas, mas funcionam efetivamente para mim. Desde que eu os goste e não os empurre para colegas mais jovens, tudo bem. No momento em que preciso compartilhá-los - eu passo pelo processo padrão de desenvolvimento de software.


11
ponto positivo: eu gosto do termo "programa" sobre "script".
glenn jackman

5

Devo dizer que estou um pouco horrorizado com as implicações das primeiras partes da pergunta. As linguagens de script Unix são linguagens de programação completas, e linguagens de programação são linguagens , o que significa que são tão infinitamente maleáveis ​​e flexíveis quanto as linguagens humanas. E uma das características da "maleabilidade e flexibilidade infinitas" é que quase nunca existe uma "maneira certa" de expressar algo - existem várias maneiras, e isso é uma coisa boa! Então, sim, é claro que é uma questão de preferência pessoal, e não há nada de errado nisso. Quem diz que há apenas uma maneira de fazer alguma coisa,

Era uma vez, a minha própria ~/binera cheia de pequenos scripts "úteis" que eu tinha escrito. Mas percebi que a maioria deles se acostumou no dia em que os escrevi e nunca mais. Portanto, quanto mais tempo passa, menor o meu bindiretório.

Eu não acho que haja algo errado em escrever um script. Se você imagina que você ou outra pessoa pode usá-lo novamente, escreva um script. Se você deseja "projetar adequadamente" um script suportável, por todos os meios, faça-o. (Mesmo que ninguém nunca use, escrever é uma boa prática.)

Razões pelas quais não escrevo mais scripts (e, acho, favorecem "one-liners"):

  • bina desordem de diretório tem um custo. Eu não coloco as coisas mais lá, a menos que elas realmente pertençam a ela.
  • As linguagens de script que eu uso são linguagens que eu uso ; Eu sou muito fácil com eles agora. Redigitar novamente uma linha sempre que eu precisar não parece um trabalho; Eu não sinto um mandato para manter, salvar e usar um script apenas para aliviar a carga de (re) digitação. (Entre outras coisas, em algum momento, a carga de redigitação se torna menor que a carga de memória de lembrar o que é um script.)
  • Outro motivo para redigitar as coisas não parece um fardo: o histórico de comandos. Existem muitas frases que não consertei como scripts, mesmo que eu as use todos os dias - mas não preciso digitá-las novamente; Eu apenas me lembro deles da história. Dessa forma, são uma espécie de scripts ou pseudônimos de homem pobre.

4

Acredito que na maioria das vezes o pedido de "uma linha" seja de fato um pedido de "mordida de som", ou seja:

No contexto do jornalismo, uma mordida sonora é caracterizada por uma frase curta ou frase que captura a essência do que o orador estava tentando dizer e é usada para resumir informações ...

As pessoas desejam e solicitam o código mais curto que demonstre uma solução para a pergunta.

Às vezes, não há como reduzir um discurso a uma "mordida no som", assim como pode ser impossível reduzir um script a um "one-liner" curto. Nesses casos, a única resposta possível é um script.

E, em geral, uma "mordida no som" nunca é um bom substituto de todo o discurso. Portanto, um "one liner" geralmente é bom apenas para transmitir uma idéia ou para dar um exemplo prático dessa idéia. Depois que a ideia for entendida, ela deverá ser expandida (aplicada) em um script.

Então, escreva uma "linha única" para transmitir uma ideia ou conceito.

Escreva seu código geral como scripts completos, não one-liners.


1

Você pergunta sobre "medo e desdém de scripts". Isso ocorre devido à situação de perguntas e respostas, onde muitas vezes a resposta está dizendo: Ele precisa dessa etapa e da seguinte, mas também posso colocá-la em uma linha (para que você possa copiar, colá-lo e usá-lo como um longo e simples comando).

Às vezes, você pode apenas adivinhar se o Q é melhor atendido por uma solução de colar de cópia rápida e suja ou se um script "legal" é exatamente o que o Q precisa entender.

Muitos dos prós e contras aqui são verdadeiros, mas ainda estão perdendo o sentido. Eu diria mesmo que as definições no Q não são úteis.

Os arquivos de histórico do shell são "one liners", mas ainda são salvos. A função bash operate-and-get-next (C-o)ainda permite que você as repita de forma semi-automática.

Quase não vejo a palavra função mencionada. Essa é a maneira de armazenar "scripts" e "one liners". E com algumas teclas, você pode alternar entre os dois formatos. Um comando composto geralmente pode ser compatível com ambos.

history -r fileé a maneira de ler uma ou várias linhas de comando (e comentários) de qualquer arquivo, não apenas do arquivo de histórico padrão. É preciso apenas uma organização mínima. Você não deve confiar em um tamanho grande de arquivo de histórico e na pesquisa de histórico para recuperar (algumas) versões de uma linha de comando.

As funções devem ser definidas de maneira semelhante. Para iniciantes, coloque thisfunc() {...}em um arquivo "funções" em seu diretório pessoal e faça a origem dele. Sim, isso é uma sobrecarga, mas é a solução geral.

Se você armazenar todas as linhas de comando e todas as variações de script em um arquivo separado, será um desperdício (teórico, mas objetivo) de blocos do sistema de arquivos.

Um one-liner não tem nada rápido e sujo por si só. É mais a parte de copiar e colar que é um pouco desaprovada e como dependemos do histórico de comandos para salvá-lo para nós.


@sitaram: seu um forro tem realmente un-onelinerish características: linha shebang, nova linha, quatro chamadas de serviços públicos - dois deles sed "programas". Eu acho que o script perl original parecia melhor, rodava mais rápido e não desperdiçava bytes, espalhando-se em 60 linhas. E o perl também permite que você aperte um pouco.

Para mim, esse é exatamente o tipo de linha a evitar. Você gostaria de ter isso (colado) na sua linha de comando? Não, e se você armazená-lo em um arquivo de qualquer maneira (não importa script ou função), poderá investir dois ou três novos bytes de linha para fazer com que pareça agradável.


10 min. mais tarde: eu só queria verificar se posso dizer "dois programas sed" ou se trata de "duas substituições / chamadas sed". Mas a resposta do sitaram se foi. Minha resposta ainda faz sentido, espero.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.