【问题标题】:Wrap indented lines back to previous line将缩进的行换回上一行
【发布时间】:2021-11-05 11:49:54
【问题描述】:

我想转以下输入:

May 13 00:29:49 BBAOMACBOOKAIR2 com.apple.xpc.launchd[1] (com.apple.mdworker.bundles[12610]): Service exited with abnormal code: 78
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:
    ASL Module "com.apple.cdscheduler" claims selected messages.
    Those messages may not appear in standard system log files or in the ASL database.
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:
    ASL Module "com.apple.install" claims selected messages.
    Those messages may not appear in standard system log files or in the ASL database.

进入以下输出:

May 13 00:29:49 BBAOMACBOOKAIR2 com.apple.xpc.launchd[1] (com.apple.mdworker.bundles[12610]): Service exited with abnormal code: 78
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:ASL Module "com.apple.cdscheduler" claims selected messages.Those messages may not appear in standard system log files or in the ASL database.
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:ASL Module "com.apple.install" claims selected messages.Those messages may not appear in standard system log files or in the ASL database.

也就是说,缩进的行应该连接到前面的非缩进行。

我已经有一个 PowerShell 解决方案,但现在我需要一个使用 native macOS 实用程序的解决方案,例如 bash 解决方案。

这里是 PowerShell 解决方案,从 this answer 到我之前的问题:

  $mergedLine = ''
  switch -Regex -File file.log {
    '^\S' {  # 'May ...' line, no leading whitespace.
      if ($mergedLine) { $mergedLine } # output previous 
      $mergedLine = $_
    }
    default { # Subsequent, indented line (leading whitespace)
      $mergedLine += ' ' + $_.TrimStart()
    }
  }
  $mergedLine # output final merged line

这是我将其转换为bash 脚本的尝试:

file=/xx
OIFS=$IFS
IFS=
while read -r line
do
case $line in
        [a-zA-Z]*)
        if [ $line ];then
        line=$line
        fi
        y=$line
        ;;
        *)
        line=$y$line
        ;;
esac
echo $line
done <$file
IFS=$OIFS

不幸的是,它没有按预期工作,因为我收到以下输出:

May 13 00:29:49 BBAOMACBOOKAIR2 com.apple.xpc.launchd[1] (com.apple.mdworker.bundles[12610]): Service exited with abnormal code: 78
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice: ASL Module "com.apple.cdscheduler" claims selected messages.
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice: Those messages may not appear in standard system log files or in the ASL database.
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice:
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice: ASL Module "com.apple.install" claims selected messages.
May 13 00:30:00 BBAOMACBOOKAIR2 syslogd[113]: Configuration Notice: Those messages may not appear in standard system log files or in the ASL database.

【问题讨论】:

  • 很好听。仅供参考:PowerShell(核心)也runs on a mac
  • @iRon 我知道可以。但我仍然需要 bash/shell。如果可以,请撤消您对这个问题的投票。谢谢。
  • 对 PowerShell 版本的评论:您使用 .Net 类 System.IO.StreamReader(而不是本机 Get-Content cmdlet)可能用于 performance reasons,但类似于 building object collections,字符串是不可变的,并且因此,增加赋值运算符 (+=) 可能会变得相当昂贵。相反,您最好将每一行放在管道上,然后-Join 他们一次。
  • @iRon 是的,因为性能。文件太大。谢谢你的建议。我也将学习如何提出一个好问题。

标签: bash macos powershell shell


【解决方案1】:

这是一个解决方案,它对您的脚本应用最少的修改以使其正常工作。但是,我建议在此之前使用 @mklement0 的基于 awk 的解决方案。

file=/xx
OIFS=$IFS
IFS=
while read -r line
do
    case $line in
        [a-zA-Z]*)
        if [ "$formatted_line" ];then
            echo "$formatted_line"
        fi
        formatted_line="$line"
        ;;
        *)
        formatted_line="$formatted_line $line"
        ;;
    esac
done <$file
if [ "$formatted_line" ];then
    echo "$formatted_line"
fi
IFS=$OIFS

【讨论】:

    【解决方案2】:
    • 在 Unix 实用程序领域,awk 与 PowerShell 的 switch 语句在概念上基本相似[1],PowerShell 解决方案所基于。

    • 作为一个外部编译实用程序,awk 远远优于任何用纯 (bash) shell 代码编写的解决方案,例如 while / case 基于循环的解决方案尝试过你的问题。

    等效(便携式)awk 解决方案是:

    awk '
      /^[^[:blank:]]/ {                   # line starts with non-whitespace char.
        if (length(mergedLines)>0) { print mergedLines } # print previous merged line
        mergedLines = $0                  # start new merged line
        next 
      }
      {                                   # indented line
        sub(/^[[:blank:]]+/, "")          # trim leading whitespace
        mergedLines = mergedLines " " $0  # join to previous lines
      }
      END { 
        print mergedLines                 # print last merged line
      }
    ' file.log
    

    请注意,ma​​cOS 附带的awk 版本大多仅限于 POSIX 强制功能,而 GNU Awk (gawk) - 可在 Mac 上按需安装 - 提供许多附加功能 strong>,例如方便的字符类快捷方式 \S\s 代替 ^[:blank:][:blank:](尽管从技术上讲,严格的等价物是 ^[:space:][:space:],但是 intra-行,没有区别),在 PowerShell 使用的 .NET 正则表达式实现中也可用。

    tripleee 建议使用以下简化的、更多的awk-惯用变体:

    awk '
      /^[[:blank:]]/ {           # indented line
        sub(/^[[:blank:]]/, "")  # trim leading whitespace
        merged = merged " " $0   # join to previous lines
        next
      }
      merged {                   # previous merged line exists?
        print merged             # print previous
      }
      {                          # line starts with non-whitespace char.
        merged = $0              # start new merged line  
      }
      END {
        print merged             # print last merged line
      }
    ' file.log
    

    [1] 事实上,更古老的awk 启发了 PowerShell 的switch 声明。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-23
      • 2011-02-15
      • 1970-01-01
      • 2022-07-30
      • 2011-08-13
      • 2013-03-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多