You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何提取命令上方最近的无前置空白#起始行(支持空行间隔)

问题描述

需要在shell脚本中执行命令时,打印该命令上方最后一行行首无空格/制表符且以#开头的注释行,即使命令与该行之间存在空行。

示例脚本:

#!/bin/ksh
# foobar1
   # foobar2
my command here to print the line above which starts with #


# another foobar

sleep 1
    if [ "1" -eq "1" ]; do
         sleep 1
         my command here to print the line above which starts with #
    fi

预期输出:

# foobar1
# another foobar

此前尝试的命令 grep -B1 '^[^#]' $0 | head -1 无法处理命令与注释行之间有空行的场景,因为空行也会被匹配为^[^#],导致取到错误的行。


解决方案

使用awk结合当前行号$LINENO实现,它可以逐行跟踪符合条件的注释行,直到找到目标命令行,输出最近的有效注释。

将脚本中的目标命令替换为以下awk命令:

awk -v cmd_line="$LINENO" '
    BEGIN { target = cmd_line }
    NR < target {
        if (/^#/) { last_valid = $0 }
    }
    NR == target { print last_valid }
' "$0"

替换后的完整脚本
#!/bin/ksh
# foobar1
   # foobar2
awk -v cmd_line="$LINENO" '
    BEGIN { target = cmd_line }
    NR < target {
        if (/^#/) { last_valid = $0 }
    }
    NR == target { print last_valid }
' "$0"


# another foobar

sleep 1
    if [ "1" -eq "1" ]; then
         sleep 1
         awk -v cmd_line="$LINENO" '
             BEGIN { target = cmd_line }
             NR < target {
                 if (/^#/) { last_valid = $0 }
             }
             NR == target { print last_valid }
         ' "$0"
    fi

原理说明
  1. -v cmd_line="$LINENO":将当前命令所在的行号传递给awk的target变量,明确要定位的目标行。
  2. NR < target:在处理到目标行之前,逐行检查每一行:如果行首直接以#开头(无前置空格/制表符),就更新last_valid变量为该行内容,始终保留最近的有效注释行。
  3. NR == target:当处理到目标命令行时,输出last_valid变量中存储的最近有效注释行。

原grep命令失效的原因:grep -B1 '^[^#]' $0会匹配所有非#开头的行,包括空行(空行的行首不属于#),导致当注释行与命令之间有空行时,grep会取空行的前一行,而非命令对应的最近有效注释行。

内容的提问来源于stack exchange,提问作者Feriman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 13:45:29