Tenho notado muitas perguntas e respostas e comentários expressando desdém por (e às vezes até medo de) escrever scripts em vez de frases curtas. Então, gostaria de saber:
Quando e por que devo escrever um script autônomo 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 um ou outro 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 pipelines e/ou uso de linguagens comosed
,awk
,perl
, e/ou ferramentas comogrep
oucut
ousort
.É 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 for 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(s) interpretado(s) que são salvos em um arquivo e, em seguida, executados. Um script pode ser escrito inteiramente em um idioma, ou pode ser um wrapper de shell-script em torno de vários "one-liners" usando outros idiomas.
Eu tenho minha própria resposta (que postarei mais tarde), mas quero que isso se torne um Q&A canônico sobre o assunto, não apenas minha opinião pessoal.
Outra resposta baseada na experiência prática.
Eu usaria um one-liner se fosse um código "jogar fora" que eu pudesse escrever diretamente no prompt. Por exemplo, eu poderia usar isso:
Eu usaria um script se decidisse que vale a pena salvar o código. Nesse ponto, eu adicionaria uma descrição na parte superior do arquivo, provavelmente adicionaria alguma verificação de erros e talvez até o verificasse em um repositório de código para controle de versão. 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, a linha acima poderia ser expandida para isso:
Generalizando, pode-se dizer
Uma linha
Roteiro
cron
)Eu vejo um bom número de perguntas aqui no unix.SE pedindo um one-liner para executar uma tarefa específica. Usando meus exemplos acima, acho que o segundo é muito mais compreensível do 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 espremido em uma linha para qualquer coisa que não seja a mais trivial das soluções.
Escreva um script quando:
Escreva um one-liner quando:
Quando uma série de comandos necessária é bastante curta e/ou produz um resultado que pode ser usado como parte de um pipeline maior ou um alias de comando, pode ser uma boa linha.
Basicamente, acho que one-liners geralmente são coisas que um administrador de sistema experiente familiarizado com o problema e os comandos usados pode escrever no local, sem pensar muito.
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 uma função shell, para facilitar a leitura. Além disso, se é algo que você escreve para ser usado repetidamente, ou algo que será usado (e possivelmente solucionado) por outras pessoas, você deve estar disposto a gastar o tempo para escrever a solução em um texto claro (er), comentado, formulário de roteiro.
No Python, a indentação faz parte da sintaxe, portanto, você literalmente não pode usar os recursos da linguagem em toda a sua extensão se escrever uma linha.
Perl e awk one-liners geralmente são sobre o uso do poder bruto das expressões regulares. Mas alguns chamam as expressões regulares de Linguagem Somente Gravação, não totalmente sem razão. Escrever um script de várias linhas permite que você escreva comentários para descrever o que uma determinada expressão regular 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 compensações entre legibilidade e compactação; tudo isso são questões de julgamento pessoal. Até mesmo a escolha de um idioma pode depender de questões pessoais: se um idioma específico seria teoricamente ideal para um determinado problema, mas você não está familiarizado com ele e já sabe como resolver o problema com outro idioma, você pode escolher o linguagem familiar para realizar 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 é inimigo do bom o suficiente , e isso se aplica muito aqui.
E se você estiver familiarizado com Perl, você já deve ter ouvido falar de TMTOWTDI: Há mais de uma maneira de fazer isso.
Observe que esta é uma opinião pessoal; tome-o com um grão de sal.
Se o comando caber em, digamos, 80 caracteres, use uma linha. Linhas de comando longas são difíceis de trabalhar. Há também o problema da recorrência, veja #2
Se você precisar executar o(s) comando(s) mais de uma vez, use um script. Caso contrário, use uma linha única, desde que a condição nº 1 seja atendida.
Eu vejo e uso um one-liner como uma ferramenta de desenvolvimento temporária para editar repetidamente até que ele faça o que eu quero, ou eu entendo como alguma sutileza de um subcomando funciona.
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 no meu PATH de lixeira pessoal, possivelmente para refinamento, parametrização e assim por diante. Normalmente, uma linha será dividida para mais legível, mesmo que nenhuma outra alteração seja feita ou eu nunca use o script novamente.
Eu configurei meu histórico de shell para ter mais de 5.000 linhas, com um histórico separado por terminal e por login em um controle remoto e assim por diante. Odeio não conseguir encontrar nesses históricos um comando de uma linha que desenvolvi há algumas semanas e não achei que precisaria de novo, daí minha estratégia.
Às vezes, um grupo inteiro de comandos é necessário para fazer alguma coisa, como configurar algum hardware; no final, copio-os todos do histórico, limpo-os minimamente e adiciono-os a um script de shell
RUNME
apenas como notas sobre o que fiz, mas também para que estejam quase prontos para serem usados novamente por outra pessoa. (É por isso que eu acho que ferramentas que fornecem apenas uma GUI para configurá-las uma dor.) Acho isso um ganho incrível em eficiência, pois muitas vezes algo que você espera fazer apenas uma vez, tem que ser feito outras 5 vezes. .Eu gostaria que as pessoas da minha equipe escrevessem scripts para quaisquer operações que precisem ser executadas mais de uma vez (ou seja, "fluxos de trabalho" ou "pipelines") e para qualquer tarefa única que precise ser documentada (normalmente coisas como "modificar certas coisas em algum conjunto de dados para corrigir dados fornecidos incorretamente" no nosso caso). Além disso, "one-liners" ou scripts não importam muito.
Deixar de documentar adequadamente os fluxos de trabalho (como scripts ou equivalentes) dificulta a introdução de novos funcionários em um projeto e também dificulta a transição de pessoas de um projeto. Além disso, dificulta qualquer tipo de auditoria, e rastrear bugs pode ser impossível.
Isso é independente de qual linguagem é usada para programação.
Outros locais de trabalho podem ter costumes ou expectativas semelhantes/diferentes, talvez até mesmo por escrito.
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 U&L, ou sempre que preciso testar os componentes individuais de um comando ou conjunto de comandos antes de executá-lo "para real".
Eu também escrevo scripts para tarefas repetitivas que eu realmente quero fazer da mesma maneira todas as vezes, mesmo que sejam simples, como
Eu uso funções de shell (muito raramente aliases) por conveniência em shells interativos, por exemplo, para adicionar opções a certos comandos por padrão (
-F
forls
) ou para criar variações especializadas de alguns comandos (pman
aqui está umman
comando que apenas analisa manuais POSIX, por exemplo) .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 elas 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 há "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 com isso. Qualquer um que diga que só há uma maneira de fazer alguma coisa,
Era uma vez, o meu próprio roteiro
~/bin
estava cheio de pequenos roteiros "úteis" que escrevi. Mas percebi que a maioria deles se acostumou no dia em que os escrevi, e nunca mais. Então, quanto mais tempo passa, menorbin
fica meu diretório.Acho que não há nada de errado em escrever um roteiro. Se você imaginar que você ou outra pessoa pode usá-lo novamente, de qualquer forma, escreva um script. Se você quiser "projetar adequadamente" um script suportável por causa disso, faça-o. (Mesmo que ninguém o use, escrevê-lo é uma boa prática.)
Razões pelas quais eu não escrevo mais scripts (e, eu acho, favoreço "one-liners"):
bin
a desordem de diretórios tem um custo. Eu não coloco mais coisas lá, a menos que elas realmente pertençam lá.Parece que tenho uma opinião minoritária sobre isso.
O termo "script" é intencionalmente confuso, livre-se dele. Este é o software que você está escrevendo lá, mesmo se estiver usando apenas
bash
eawk
.Dentro de uma equipe, prefiro escrever software com processo de revisão de código aplicado por uma ferramenta (github/gitlab/gerrit). Isso dá 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ê tem uma equipe de administradores, o mais simples
vim /root/bin/x.sh
é principalmente um desastre em termos de comunicação relacionada a alterações, legibilidade de código e distribuição entre sistemas. Muitas vezes, um mau funcionamento grave custa mais tempo/dinheiro do que o processo supostamente "pesado".Eu prefiro one-liners, na verdade, para qualquer coisa que não mereça esse processo "pesado". Eles podem ser reutilizados rapidamente, com poucas teclas, se você souber como usar seu histórico de shell de forma eficaz; facilmente colado entre sistemas não relacionados (por exemplo, clientes diferentes).
Diferença crucial entre (não revisado!) one-liners e o software revisado ("scripts"): a responsabilidade é totalmente sua quando você executa one-liners. Você nunca pode dizer a si mesmo "Acabei de encontrar este one-liner em algum lugar, executei-o sem entender, o que se seguiu não é minha culpa" - você sabia que está executando um software não revisado e não testado, então a culpa é sua. Certifique-se de que seja pequeno o suficiente para que você possa prever os resultados - que se dane se não o fizer.
Você precisa dessa abordagem simplista às vezes, 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 das minhas frases parecem terrivelmente longas, mas funcionam efetivamente para mim. Contanto que eu os groque e não enfie isso em colegas mais juniores, está tudo bem. No momento em que preciso compartilhá-los, passo pelo processo padrão de desenvolvimento de software.
Acredito que na maioria das vezes o pedido de "one-liner" é na verdade um pedido de "sound bite", ou seja:
As pessoas querem e solicitam o código mais curto que demonstre uma solução para a pergunta feita.
Às vezes, não há como reduzir um discurso a uma "frase sonora", assim como pode ser impossível reduzir um script a uma curta "linha". Nesses casos, a única resposta possível é um script.
E, em geral, um “sound bite” nunca é um bom substituto de todo o discurso. Assim, um "one liner" geralmente só serve para transmitir uma ideia ou para dar um exemplo prático dessa ideia. Então, depois que a ideia é compreendida, ela deve ser expandida (aplicada) em um script.
Então, escreva um "one-liner" para transmitir uma ideia ou conceito.
Escreva seu código geral como scripts completos e não como uma linha.
Você pergunta sobre "medo e desdém de roteiros". Isso se deve à situação Q+A, onde muitas vezes a resposta está dizendo: Ele precisa desta etapa e desta, mas também posso colocá-lo em uma linha (para que você possa copiar e colar e usá-lo como um comando longo e simples).
Às vezes, você só pode adivinhar se o Q é melhor servido por uma solução de copiar e colar 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 assim eles estão perdendo o ponto. Eu diria até 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)
permite até mesmo repeti-los semi-automaticamente.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 se encaixar em 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. Leva apenas alguma organização mínima. Você não deve confiar em um grande tamanho de arquivo de histórico e pesquisa de histórico para recuperar (alguma) versão de uma linha de comando.As funções devem ser definidas de maneira semelhante. Para começar, coloque
thisfunc() {...}
um arquivo "functions" em seu diretório inicial e obtenha-o. Sim, isso é uma sobrecarga, mas é a solução geral.Se você armazenar cada linha de comando e cada variação de script em um arquivo separado, é 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 apenas confiamos no histórico de comandos para salvá-lo para nós.
@sitaram: seu one liner realmente tem recursos un-onelinerish : shebang line, newline, quatro chamadas de utilitário - duas delas sed "programs". Eu acho que o script perl original ficou mais bonito e correu mais rápido e não desperdiçou nenhum byte espalhando-se em 60 linhas. E o perl também permite que você esprema um pouco.
Para mim, esse é exatamente o tipo de um forro a evitar. Você gostaria de ter isso (colado) em sua linha de comando? Não, e então, se você armazená-lo em um arquivo de qualquer maneira (não importa o script ou a função), você pode investir dois ou três bytes de nova linha para torná-lo --- agradável.
10 min. depois: Eu só queria verificar se posso dizer "dois programas de sed" ou "duas substituições/chamadas de sed". Mas a resposta do sitaram se foi. Minha resposta ainda faz sentido, espero.