将缩进行换回前一行



我想转换以下输入:

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解决方案,但是现在我需要一个使用原生macOS实用程序的解决方案,比如bash解决方案。

下面是PowerShell的解决方案,从这个答案到我之前的问题:

$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.

  • 在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

注意macOS自带的awk版本主要限于posix强制功能GNUAwk (gawk) -可在mac上按需安装-提供了许多额外的功能,例如方便的字符类快捷方式Ss代替^[:blank:][:blank:](虽然,从技术上讲,严格等效的是^[:space:][:space:],但是-行中没有区别),PowerShell利用的。net regex实现中也有。

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语句。

这是一个对脚本进行最小修改以使其正常工作的解决方案。但是,我建议在此之前使用@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

相关内容

  • 没有找到相关文章

最新更新