AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 544428
Accepted
cas
cas
Asked: 2019-10-01 02:06:39 +0800 CST2019-10-01 02:06:39 +0800 CST 2019-10-01 02:06:39 +0800 CST

单行与脚本

  • 772

我注意到很多问题、答案和评论表示不屑(有时甚至害怕)编写脚本而不是单行代码。所以,我想知道:

  • 何时以及为什么要编写独立脚本而不是“单行”?或相反亦然?

  • 两者的用例和优缺点是什么?

  • 某些语言(例如 awk 或 perl)是否比其他语言(例如 python)更适合单行代码?如果是这样,为什么?

  • 这只是个人喜好问题,还是有好的(即客观的)理由在特定情况下写一个或另一个?这些原因是什么?

定义

  • one-liner: 直接键入或粘贴到 shell 命令行中的任何命令序列。通常涉及管道和/或使用诸如sed、awk、perl和/或工具之类的语言grep或cut或sort.

    定义特征是在命令行上直接执行 - 长度和格式无关紧要。“单行”可能全部在一行,也可能有多行(例如 sh for 循环,或嵌入的 awk 或 sed 代码,带有换行和缩进以提高可读性)。

  • script: 任何解释语言的命令序列,保存到文件中,然后执行。脚本可以完全用一种语言编写,也可以是使用其他语言的多个“单行”的外壳脚本包装器。


我有自己的答案(稍后会发布),但我希望这成为关于该主题的规范问答,而不仅仅是我的个人意见。

scripting
  • 10 10 个回答
  • 8282 Views

10 个回答

  • Voted
  1. Best Answer
    roaima
    2019-10-01T02:59:43+08:002019-10-01T02:59:43+08:00

    另一种基于实践经验的回应。

    如果它是我可以在提示符下直接编写的“丢弃”代码,我会使用单行代码。例如,我可能会使用这个:

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

    如果我认为代码值得保存,我会使用脚本。此时我会在文件顶部添加描述,可能会添加一些错误检查,甚至可能会将其检入代码存储库以进行版本控制。例如,如果我决定检查一组服务器的正常运行时间是一个有用的功能,我会一次又一次地使用,那么上面的单线可能会扩展为:

    #!/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
    

    概括地说,可以说

    • 单线

      • 为特定的一次性目的而编写的简单代码(即只是“一些”语句)
      • 可以在需要时快速轻松地编写代码
      • 一次性代码
    • 脚本

      • 将(可能)使用不止一次或两次的代码
      • 需要多于“一些”语句的复杂代码
      • 需要由其他人维护的代码
      • 其他人可以理解的代码
      • 无人值守运行的代码(例如,从cron)

    我在unix.SE上看到了相当多的问题,要求单线执行特定任务。使用我上面的例子,我认为第二个比第一个更容易理解,因此读者可以从中学到更多。一个解决方案可以很容易地从另一个解决方案派生出来,因此为了可读性(对于未来的读者),我们可能应该避免将代码挤在一行中,而不是最微不足道的解决方案。

    • 34
  2. dr_
    2019-10-01T02:23:28+08:002019-10-01T02:23:28+08:00

    在以下情况下编写脚本:

    • 需要更多代码
    • 你重视可读性
    • 添加注释是必要/有用的,以显示代码的作用
    • 你需要传递参数
    • 您希望脚本在自己的环境中运行(变量等)
    • 您可能会为了更复杂的目的重用/调整代码

    在以下情况下写一行:

    • 只需要少量代码
    • 您想访问在当前 shell 中定义的变量
    • 你需要一个快速而肮脏的解决方案
    • 11
  3. telcoM
    2019-10-01T02:44:53+08:002019-10-01T02:44:53+08:00

    当所需的一系列命令相当短和/或产生可用作较大管道或命令别名的一部分的结果时,它可能是一个很好的单行。

    基本上,我认为单行代码通常是熟悉问题和使用的命令的经验丰富的系统管理员可能会在现场编写的东西,而无需过多思考。

    当单行代码变得过长或涉及的不仅仅是非常简单的条件或循环时,通常最好将它们编写为多行脚本或 shell 函数,以提高可读性。此外,如果它是您编写的要反复使用的东西,或者将被其他人使用(并且可能会遇到麻烦)的东西,您应该愿意花时间将解决方案写成清晰(呃),评论说,脚本形式。

    在 Python 中,缩进是语法的一部分,因此如果您编写单行代码,您实际上无法充分利用该语言的特性。

    Perl 和 awk 单行语句通常是关于使用正则表达式的原始功能。但有些人称正则表达式为只写语言,并非完全没有理由。编写多行脚本允许您在注释中写下特定的正则表达式应该做什么,这将非常有帮助,当您再次查看该脚本时,在其间做了六个月的其他事情之后。

    这本质上是一个非常基于意见的问题,因为它涉及衡量可接受的复杂程度以及可读性和紧凑性之间的权衡;所有这些都非常取决于个人判断。甚至选择一种语言也可能取决于个人问题:如果一种特定语言在理论上最适合特定问题,但您不熟悉它,并且已经知道如何用其他语言解决问题,您可以选择熟悉的语言,以便以最少的努力快速完成工作,尽管该解决方案在技术上可能有些低效。

    最好的往往是足够好的敌人,这在这里非常适用。

    如果您熟悉 Perl,您可能已经听说过 TMTOWTDI:有不止一种方法可以做到。

    • 9
  4. schaiba
    2019-10-01T02:22:29+08:002019-10-01T02:22:29+08:00

    请注意,这是个人意见;带着一粒盐吃。

    1. 如果命令适合,例如 80 个字符,请使用单行。长命令行很难使用。还有重复的问题,见#2

    2. 如果您需要多次运行命令,请使用脚本。否则,只要满足条件#1,就使用单线。

    3. 这是非常主观的,但是是的,我认为 shell、Perl 或 awk 是我用于单行代码的首选工具。
    4. 参见#1、#2、#3。
    • 8
  5. meuh
    2019-10-01T03:13:35+08:002019-10-01T03:13:35+08:00

    我查看并使用单线作为一种临时开发工具来反复编辑,直到它完成我想要的,或者我了解子命令的一些微妙之处是如何工作的。

    然后,它要么在我正在调查的主题的文本文件中被记录(和注释),要么被清理成一个放在我个人 bin PATH 中的脚本,可能用于进一步细化、参数化等。通常,即使没有进行其他更改,或者我再也不会使用该脚本,也会将这一行分解为更具可读性。

    我将我的 shell 历史记录设置为超过 5000 行,每个终端都有单独的历史记录,每次远程登录等等。我讨厌无法在这些历史记录中找到我几周前开发的单行命令,并且认为我不再需要,因此我的策略。

    有时,一整组命令需要做一些事情,比如配置一些硬件;最后,我将它们全部从历史记录中复制出来,进行最低限度的清理,并将它们添加到 shell 脚本RUNME中,就像我所做的注释一样,而且它们几乎可以被其他人再次使用。(这就是为什么我发现只提供 GUI 来配置它们的工具如此痛苦的原因。)我发现这是一个令人难以置信的效率提升,因为通常你希望只做一次的事情,然后必须再做 5 次。 .

    • 7
  6. Kusalananda
    2019-10-01T04:22:21+08:002019-10-01T04:22:21+08:00

    我希望我的团队中的人员为可能需要多次执行的任何操作(即“工作流”或“管道”)以及任何需要记录的一次性任务(通常在我们的案例中,诸如“修改某些数据集中的某些内容以修复错误提供的数据”之类的东西)。除此之外,“单行”或脚本并不重要。

    未能正确记录工作流程(作为脚本或同等文件)会使在项目中引入新员工变得更加困难,并且也使人们更难以从项目中转移出来。它还使任何类型的审计都变得困难,并且可能无法追踪错误。

    这与用于编程的语言无关。

    其他工作场所可能有相似/不同的习俗或期望,甚至可能被记录下来。

    在家里,你做任何你想做的事。

    例如,当我在 shell 中做一些重要的事情时,我会立即编写脚本,比如在提交对 U&L 问题的答案之前,或者每当我需要在运行命令或命令集之前测试它的各个组件“for真实的”。

    我还为重复性任务编写脚本,我真的希望每次都以相同的方式执行,即使它们很简单,比如

    • 更新我的 OpenBSD 系统和所有已安装的软件包(这归结为三个简短的命令,以及一些其他用于管理的命令,收集在一个简短的脚本中),或者
    • 将我的系统备份到异地存储(本质上是一个命令,但同样需要大量的内务处理,脚本还允许我在快照等之间进行差异,并且它需要在不同系统上的工作方式略有不同,并且我从 cron 作业运行它),或者
    • 获取邮件(同样,本质上是一个命令,但我希望它在作为 cron 作业调用和从命令行使用它时表现不同,并且在某些情况下它不应该尝试获取邮件,它会写一个短日志消息到文件)。

    为了方便交互式 shell,我使用 shell 函数(很少使用别名),例如,默认情况下为某些命令添加选项(-Ffor ls)或创建某些命令的特殊变体(例如,pman这里是一个man仅查看 POSIX 手册的命令) .

    • 5
  7. Steve Summit
    2019-10-01T19:28:11+08:002019-10-01T19:28:11+08:00

    我必须说我对问题第一部分的含义感到有些震惊。Unix 脚本语言是成熟的编程语言,而编程语言是语言,这意味着它们与人类语言一样具有无限可塑性和灵活性。“无限延展性和灵活性”的标志之一是几乎从来没有“一种正确的方式”来表达某事——有多种方式,这是一件好事!所以,是的,这当然是个人喜好问题,这并没有错。任何说做事只有一种方法的人,

    曾几何时,我自己~/bin写了很多“有用”的小脚本。但我意识到它们中的大多数在我写它们的那天就被使用了,而且再也没有使用过。所以时间越长,我的bin目录就越小。

    我不认为写剧本有什么问题。如果您认为您或其他人可能会再次使用它,请务必编写一个脚本。如果您想为此“适当地设计”一个可支持的脚本,请务必这样做。(即使没有人使用它,编写它也是一种好习惯。)

    我不再写脚本的原因(而且,我猜,更喜欢“单行”):

    • bin目录混乱确实是有代价的。我不再把东西放在那里,除非它们真的属于那里。
    • 我使用的脚本语言是我使用的语言;我现在对他们真的很轻松。每当我需要时重新输入一个单行字并不像工作;我不觉得保留、保存和使用脚本只是为了减轻(重新)输入的负担。(除其他外,在某些时候,重新输入的负担变得比记住脚本是什么的记忆负担要小。)
    • 重新输入内容不会让人感到负担的另一个原因是:命令历史记录。尽管我每天都在使用它们,但我没有将许多单行文字写成脚本——但我不必重新输入它们;我只是从历史中回忆起他们。这样一来,它们就像是穷人的脚本或别名。
    • 5
  8. kubanczyk
    2019-10-02T14:26:23+08:002019-10-02T14:26:23+08:00

    看来我对此持少数观点。

    术语“脚本”故意混淆,摆脱它。这是您正在那里编写的软件,即使您只使用bash和awk.

    在团队中,我更喜欢使用由工具(github/gitlab/gerrit)强制执行的代码审查过程来编写软件。这提供了版本控制作为奖励。如果您有多个系统,请添加持续部署工具。如果目标系统很重要,还有一些测试套件。我对这些并不虔诚,但会权衡收益和成本。

    如果您有一个管理员团队,那么最简单vim /root/bin/x.sh的方式主要是与变更相关的沟通、代码可读性和跨系统分发方面的灾难。通常,一个严重的故障比所谓的“繁重”过程花费更多的时间/金钱。

    对于任何不值得“繁重”过程的东西,我实际上更喜欢单线。如果您知道如何有效地使用您的 shell 历史,它们可以通过几次按键快速重复使用;在不相关的系统(例如不同的客户)之间轻松粘贴。

    (未审查!)单行代码和已审查软件(“脚本”)之间的关键区别:当您执行单行代码时,责任完全在您身上。你永远不能对自己说“我只是在某个地方发现了这个单行代码,我在不理解的情况下运行了它,接下来发生的事情不是我的错”——你知道你正在运行未经审查和未经测试的软件,所以这是你的错。确保它足够小,以至于您可以预见结果-如果您不这样做,那该死的。

    有时您需要这种简单化的方法,并且将栏设置在大约一行文本在实践中效果很好(即已审核和未审核代码之间的边界)。我的一些单行字看起来长得吓人,但它们确实对我有效。只要我摸了他们,我不把它强加给更多的初级同事,一切都很好。我需要分享它们的那一刻——我经历了标准的软件开发过程。

    • 5
  9. Isaac
    2019-10-01T19:28:01+08:002019-10-01T19:28:01+08:00

    我相信大多数时候对“单行”的要求实际上是对“声音片段”的要求,即:

    在新闻语境中,原声片段的特点是一个简短的短语或句子,它抓住了说话者想说的本质,并用于总结信息......

    人们想要并要求最短的代码来演示所提出问题的解决方案。

    有时,没有办法将演讲简化为“原声片段”,也可能无法将脚本简化为简短的“单行”。在这种情况下,唯一可能的答案是脚本。

    而且,一般来说,“原声”永远不能很好地替代整个演讲。因此,“一个班轮”通常只适合传达一个想法或给出该想法的实际示例。然后,在理解了想法之后,应该在脚本中对其进行扩展(应用)。

    所以,写一个“单行”来传达一个想法或概念。

    将您的通用代码编写为完整的脚本而不是单行代码。

    • 4
  10. user373503
    2019-10-03T01:17:28+08:002019-10-03T01:17:28+08:00

    您询问“对脚本的恐惧和蔑视”。这是由于 Q+A 的情况,通常答案是:它需要这一步和这个,但我也可以把它放在一行中(这样你就可以复制粘贴它并将其用作一个很长的简单命令)。

    您有时只能猜测 Q 是否可以通过快速而肮脏的复制粘贴解决方案来更好地服务,或者“好的”脚本是否正是 Q 需要理解的内容。

    这里的许多优点和缺点都是正确的,但它们仍然没有抓住重点。我什至会说 Q 中的定义没有帮助。

    shell历史文件是“一个衬里”,但它们仍然被保存。bash 功能operate-and-get-next (C-o)甚至可以让您半自动地重复它们。

    我几乎看不到提到的功能一词。这是存储“脚本”和“单行”的方式。只需几次击键,您就可以在两种格式之间切换。复合命令通常可以同时满足两者。

    history -r file是从任何文件中读取一个或多个命令行(和注释)的方法,而不仅仅是从默认历史文件中读取。它只需要一些最小的组织。您不应该依赖大的历史文件大小和历史搜索来检索(某些)命令行版本。

    函数应该以类似的方式定义。对于初学者,thisfunc() {...}在您的主目录中放入一个文件“functions”,然后获取它。是的,这是一些开销,但它是通用解决方案。

    如果您将每个命令行和每个脚本变体存储在单独的文件中,那么(理论上,但客观上)浪费了文件系统块。

    单线器本身没有任何快速和肮脏的东西。更令人不悦的是复制粘贴部分,以及我们如何仅依靠命令历史来为我们保存它。


    @sitaram:您的一个班轮确实具有非单行功能:shebang line、newline、四个实用程序调用-其中两个是 sed“程序”。我认为原始的 perl 脚本看起来更好,运行速度更快,并且不会因为分散到 60 行而浪费任何字节。perl 还可以让你挤很多。

    对我来说,这正是要避免的那种。你想把它(粘贴)在你的命令行上吗?不,然后,如果您将它存储在一个文件中(无论是脚本还是函数),您可能会投入两三个换行字节以使其看起来不错。


    10 分钟。后来:我只是想检查我是否可以说“两个 sed 程序”或者它是“两个 sed 替换/调用”。但是西塔拉姆的答案已经消失了。我希望我的回答仍然有意义。

    • 1

相关问题

  • 检查root用户的登录历史

  • 在我的 Nginx 服务器环境中复制网站 (Wordpress) 的快速方法?

  • 启动应用程序的问题:命令行与 gui

  • 用于在日志文件中查找字符串的 Shell 脚本

  • 根据其中的值批量重命名(附加)CSV 文件

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve