Bash 用命令替换字符串

Bash 用命令替换字符串

我有一个命令(logcat),它输出一个长日志,如下所示:

07-27 09:26:22.416 17574 17886 D SurfaceControl: Excessive delay in setPowerMode()
07-27 09:26:22.421 17574 17599 I PowerManagerService: Sleeping (uid 1000)...
07-27 09:26:22.427 17489 17527 D audio_hw_primary: adev_set_parameters: enter: screen_state=off

格式为:[Date] [Time] [Process ID] [Thread ID] [Log Type] [Text]

我想查看进程的名称(或更准确地说是包),而不是进程 ID。

可以使用以下方法通过进程 ID 检索包的名称:

echo "$PKG_PID_LIST" | grep -w $PID | cut -d ' ' -f1

例如:

$ echo "$PKG_PID_LIST" | grep -w 17489 | cut -d ' ' -f1
org.lineageos.audiofx

如果您好奇,是的,我使用的是 Android,并且使用以下方法创建列表:

PKG_PID_LIST=$(eval $(pm list packages | cut -d ':' -f 2 | sed 's/^\(.*\)$/echo \"\$\(echo \1\) \$\(pidof \1\)\";/'))

最后的输出应该是这样的:

07-27 09:26:22.416 com.android.systemui 17886 D SurfaceControl: Excessive delay in setPowerMode()
07-27 09:26:22.421 com.android.systemui 17599 I PowerManagerService: Sleeping (uid 1000)...
07-27 09:26:22.427 org.lineageos.audiofx 17527 D audio_hw_primary: adev_set_parameters: enter: screen_state=off

编辑: $PKG_PID_LIST 的示例输出:

$ echo "$PKG_PID_LIST"
com.android.deskclock 18937
com.android.systemui 17574
net.osmand.srtmPlugin.paid 
com.android.bluetoothmidiservice 
org.lineageos.audiofx 17489

(未运行的包没有 PID。包名称后面总是有一个空格。)

答案1

从多个输入源读取并应用自定义操作需要awk.你可以简单地这样做

awk 'FNR==NR{pidMap[$2]=$1; next}$3 in pidMap{$3=pidMap[$3]}1' <(echo "$PKG_PID_LIST") <(logcat)

<()是 shell 提供的语法bash,它在内部运行命令并使命令的输出就像出现在文件中一样。作为第二个文件内容,我们使输出logcat出现在那里。所以awk 尝试从两个输入流中读取。

当我们一次从多个输入流读取时使用的逻辑。FNR==NR和是特殊变量,用于跟踪每个文件和整个输入流的行号。因此,对于条件,我们基本上定义了在第一个文件上运行的后面的操作,以及在第二个文件上运行的后面的操作。awkFNRNRFNR==NR{..}

所以在第一文件像流一样,我们看到输出,PKG_PID_LIST从中创建一个哈希映射,其中键为进程 ID,进程名称为值。一旦我们处理完这个文件,我们就已经将所有 PID 与其名称进行了映射。

在第二个文件中,我们使用此映射$3 in pidMap含义,第二个流中的值$3作为我们刚刚处理的键存在,我们将$3第二个流($3第三个空格分隔列)上的值更新为键的映射值。这{..}1是一个操作,awk我们指示它根据所做的修改重建行(如果没有完成修改,则打印行)。


如果您logcat连续产生输出并且您想在输出确定后运行此命令,那么我建议先将输出写入临时文件,然后通过文件作为awk.

答案2

你可以这样做:

logcat |\
_PKG4PID_="$PKG_PID_LIST" \
perl -lpe '
    %h = reverse split /\s+/, $ENV{_PKG4PID_} if $. == 1;
    s/(?:\H+\h+){2}\K(\H+)/$h{$1}/;
' 

解释:

  • 将环境变量设置_PKG4PID_为等于您的 shell 变量PKG_PID_LIST
  • 对于 读取的输入的第一行,使用键作为第二个字段和值作为第一个字段来perl初始化哈希。%h
  • 现在只需找到当前行中的第三个字段 ,/(?:\H+\h+){2}\K(\H+)/并将其替换为相应的哈希条目 ,即可$h{$1}

相关内容