【问题标题】:Equivalent of python's textwrap dedent in bash等效于 bash 中的 python 的 textwrap dedent
【发布时间】:2016-10-19 17:20:55
【问题描述】:

我在 bash 中有一个包含多行字符串的变量:

mystring="foo
          bar
          stack
          overflow"

显然,当我echo "$mystring" 时,这会产生大量缩进。在 python 中,我只需导入 textwrap 并在字符串上使用 dedent,这将我带到这里。 bash 中是否存在类似 python 的 dedent 模块?

【问题讨论】:

    标签: python string bash format


    【解决方案1】:

    您可以使用 sed 删除每行的前导空格:

    $ sed 's/^[[:space:]]*//' <<< "$mystring"
    foo
    bar
    stack
    overflow
    

    你也可以(ab)use the fact that read will remove leading and trailing spaces:

    $ while read -r line; do printf "%s\n" "$line"; done <<< "$mystring"
    foo
    bar
    stack
    overflow
    

    在您的示例中,您基本上想要删除所有空格:

    $ echo "${mystring// }"
    foo
    bar
    stack
    overflow
    

    【讨论】:

    【解决方案2】:

    不要缩进字符串,而是取消导致需要缩进的初始换行符。

    mystring="\
    foo
    bar
    stack
    overflow"
    

    【讨论】:

    • 这不符合规定的要求:我们想要源代码中的缩进。问题是,鉴于文本在源代码中缩进,当它被程序使用时如何删除它。
    • 如果您只是要剥离缩进,为什么要首先包含缩进呢?没错,我假设我们可以控制分配,但在这种情况下,有人这样定义 mystring 只是因为他们没有意识到他们可以将字符串的开头放在单独的行上,并且缩进只是为了让作业“漂亮”。
    • 缩进在源代码中,因为续行需要额外的缩进。缩进只有在运行时被消耗时才会被剥离;为了阅读它的人,它保留在源代码中。
    • 这就是我的观点。如果您在引号之后立即开始值,则您只“需要”缩进,这不是必要的。
    • @bignose 我需要缩进字符串的原因是由于 PEP8 python 样式。代码需要有一定的结构,正确缩进的字符串是其中的一部分。
    【解决方案3】:

    “此处文档”功能允许将多行字符串定义为命令的输入:

    $ cat <<_EOT_
        Lorem ipsum dolor sit amet,
            consectetur adipiscing elit.
        Morbi quis rutrum nisi, nec dignissim libero.
    _EOT_
    
        Lorem ipsum dolor sit amet,
            consectetur adipiscing elit.
        Morbi quis rutrum nisi, nec dignissim libero.
    

    Bash 手册section on here documents 描述了一个允许在源代码中缩进的选项,并在阅读文本时将其剥离:

    这里的文档

    […]

    如果重定向操作符是&lt;&lt;-,那么所有前导制表符都会从输入行中去除,并且 包含分隔符的行。这允许 shell 脚本中的 here-documents 以自然方式缩进 时尚。

    看起来像这样:

    $ cat <<-_EOT_
        Lorem ipsum dolor sit amet,
            consectetur adipiscing elit.
        Morbi quis rutrum nisi, nec dignissim libero.
    _EOT_
    
    Lorem ipsum dolor sit amet,
        consectetur adipiscing elit.
    Morbi quis rutrum nisi, nec dignissim libero.
    

    这样做的问题是它会删除 only TAB (U+0009) 缩进,而不是空格。如果您的编码风格禁止在源代码中使用 TAB 字符,那将是一个严重的限制:-(

    【讨论】:

    • 不过,我在 ubuntu 18.04 中尝试使用 bash 并且那些领先的选项卡仍然存在。对不起。
    【解决方案4】:

    这是另一种选择,在 bash 脚本中运行 python dedent 代码。

    python_dedent_script="
    import sys, textwrap
    sys.stdout.write(textwrap.dedent(sys.stdin.read()))
    "
    function dedent_print() {
        python -c "$python_dedent_script" <<< "$1"
    }
    dedent_print "
      fun( abc, 
        def, ghi )
      jkl
    "
    

    会输出:

    fun( abc, 
      def, ghi )
    jkl
    

    【讨论】:

      【解决方案5】:

      最少使用演示

      text="this is line one
            this is line two
            this is line three\n"
      dedent text
      printf "$text"
      

      功能与详情

      我复制了sed 部分from @Andreas Louv here

      dedent() {
          local -n reference="$1"
          reference="$(echo "$reference" | sed 's/^[[:space:]]*//')"
      }
      
      text="this is line one
            this is line two
            this is line three\n"
      
      echo "BEFORE DEDENT:"
      printf "$text"
      echo ""
      
      # `text` is passed by reference and gets dedented
      dedent text
      
      echo "AFTER DEDENT:"
      printf "$text"
      echo ""
      

      text 通过引用传递到dedent 函数以便对变量内部函数的修改会影响变量函数外部时间>。通过它的引用变量访问该变量,它在该函数中被嵌入。完成后,将text 打印为常规 bash 字符串。由于它包含\n 格式字符,因此将其作为格式字符串(第一个参数)传递给printf 以解释它们。

      输出:

      BEFORE DEDENT:
      this is line one
            this is line two
            this is line three
      
      AFTER DEDENT:
      this is line one
      this is line two
      this is line three
      
      

      参考资料:

      1. 我的回答展示了 Python 的 textwrap.dedent() 的好处,因此您可以看到 为什么我们也希望在 bash 中使用此功能:Multi line string with arguments. How to declare?
      2. @Andreas Louv 的 sed 东西用于删除前面的空格:Equivalent of python's textwrap dedent in bash

      【讨论】:

        猜你喜欢
        • 2010-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-23
        • 2021-09-07
        • 1970-01-01
        相关资源
        最近更新 更多