我想转换以下输入:
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上按需安装-提供了许多额外的功能,例如方便的字符类快捷方式S
和s
代替^[: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