linux 如何打印一列变量

u3r8eeie  于 2023-08-03  发布在  Linux
关注(0)|答案(4)|浏览(99)

有人能帮帮我吗?
我正在尝试打印bash脚本的命令输出,以检查SuSE产品注册
命令输出(/usr/bin/SUSEConnect --status-text)

Installed Products:
------------------------------------------

  Desktop Applications Module
  (sle-module-desktop-applications/15.2/x86_64)

  Registered

------------------------------------------

  Server Applications Module
  (sle-module-server-applications/15.2/x86_64)

  Registered

------------------------------------------

  Basesystem Module
  (sle-module-basesystem/15.2/x86_64)

  Registered

------------------------------------------

  Legacy Module
  (sle-module-legacy/15.2/x86_64)

  Not Registered

------------------------------------------

字符串
我只是过滤了一下

sudo /usr/bin/SUSEConnect --status-text|sed -r '/^\s*$/d'|tr -d '[:blank:]'|grep -Ev "^-|InstalledProducts"
DesktopApplicationsModule
(sle-module-desktop-applications/15.2/x86_64)
Registered
ServerApplicationsModule
(sle-module-server-applications/15.2/x86_64)
Registered
BasesystemModule
(sle-module-basesystem/15.2/x86_64)
Registered
LegacyModule
(sle-module-legacy/15.2/x86_64)
NotRegistered


但我想删除行(*)并打印如下

Installed Products :  DesktopApplicationsModule Registered
                      ServerApplicationsModule  Registered
                      BasesystemModule          Registered
                      LegacyModule              NotRegistered


谢谢你,

wgx48brx

wgx48brx1#

使用任何POSIX awkcolumn

$ cat tst.awk
BEGIN { OFS="\t" }
!NF { next }
{ gsub(/^[[:space:]]+|[[:space:]]+$/,"") }
NR==1 { vals[1,1] = $0; next }
/^-+$/ { ++numRows; colNr=1; next }
{
    vals[numRows,++colNr] = $0
    numCols = colNr
}
END {
    numRows -= (colNr == 1)
    for ( rowNr=1; rowNr<=numRows; rowNr++) {
        for ( colNr=1; colNr<=numCols; colNr++ ) {
            printf "%s%s", vals[rowNr,colNr], (colNr<numCols ? OFS : ORS)
        }
    }
}

字符串

$ awk -f tst.awk file | column -s $'\t' -t
Installed Products:  Desktop Applications Module  (sle-module-desktop-applications/15.2/x86_64)  Registered
                     Server Applications Module   (sle-module-server-applications/15.2/x86_64)   Registered
                     Basesystem Module            (sle-module-basesystem/15.2/x86_64)            Registered
                     Legacy Module                (sle-module-legacy/15.2/x86_64)                Not Registered


如果您愿意,可以选择只打印某些列而不是所有列,例如:

for ( rowNr=1; rowNr<=numRows; rowNr++) {
        print vals[rowNr,1], vals[rowNr,2], vals[rowNr,4]
    }

oogrdqng

oogrdqng2#

下面的代码应该适用于任何POSIX awk(使用GNU awk和macOS附带的BSD awk进行了测试):

$ awk -v RS='' -v h='Installed Products:' '
  {gsub(/^[[:space:]]*|[[:space:]]*(\n.*)?$/,"")}
  NR%3==2 {p=$0} NR%3==0 {printf("%-25s%-35s%s\n", h, p, $0); h=""}' file
Installed Products:      Desktop Applications Module        Registered
                         Server Applications Module         Registered
                         Basesystem Module                  Registered
                         Legacy Module                      Not Registered

字符串
根据实际数据调整输出字段宽度(25,35)。
说明:当RS被设置为空字符串时,记录分隔符是一个或多个空行。所有记录都经过预处理(gsub(/^[[:space:]]*|[[:space:]]*(\n.*)?$/,"")),只保留第一行,并删除前导和尾随空格。对于记录2,5,8...(应用程序名称)我们将记录存储在变量p中。对于记录3,6,9...(注册状态)我们打印当前应用程序的输出:

  • 存储在变量h中的标题,在25个字符上左对齐,
  • 存储在变量p中的应用程序名称,左对齐35个字符,
  • 注册状态,即当前记录($0)。

在第一个printf之后,我们清除header(h="")。
如果你更喜欢自动计算输出字段宽度,我们必须等到输入结束才能打印,因为我们需要知道最长的应用程序名称:

$ awk -v RS='' -v h='Installed Products:' '
  {gsub(/^[[:space:]]*|[[:space:]]*(\n.*)?$/,"")}
  NR%3==2 {p[++n]=$0; mp=length>mp?length:mp} NR%3==0 {q[n]=$0}
  END {mh=length(h)
       for(i=1;i<=n;i++)
         printf("%-*s%-*s%s\n", mh+1, i==1?h:"", mp+1, p[i], q[i])}' file
Installed Products: Desktop Applications Module Registered
                    Server Applications Module  Registered
                    Basesystem Module           Registered
                    Legacy Module               Not Registered


注意:正如其他答案所建议的那样,我们也可以使用column实用程序进行最终格式化,但我们需要为column的输入选择一个字段分隔符,这在您的主输入中找不到。除非您知道这样一个分隔符,并且100%确定在主输入中找不到它,否则只使用awk进行整个操作可能会更安全一些。

vfwfrxfs

vfwfrxfs3#

我已经将你的命令输出复制到文件'f'中做了一些测试,你不需要trgrepsed就可以删除所有不必要的东西:

$ sed -r '/^\s*$|^-|\(.*\)|^Ins/d;s/ //g' f
DesktopApplicationsModule
Registered
ServerApplicationsModule
Registered
BasesystemModule
Registered
LegacyModule
NotRegistered

字符串
现在,让我们使用printf来打印:

$ printf '%-30s%s\n' $(sed -r '/^\s*$|^-|\(.*\)|^Ins/d;s/ //g' f)
DesktopApplicationsModule     Registered
ServerApplicationsModule      Registered
BasesystemModule              Registered
LegacyModule                  NotRegistered


看起来很酷),并使它成为你想要的方式让我们这样做:

# add all data to an array
arr=( $(sed -r '/^\s*$|^-|\(.*\)|^Ins/d;s/ //g' f) )

# print initial text and first 2 items from array
printf 'Installed Products : %-30s%s\n' ${arr[@]:0:2}

# print the rest, loop over the rest of array
for ((i=2; i<${#arr[@]}; i+=2)); {
    # empty valued added here⤵ to propper alighnment
    printf '%21s%-30s%s\n'   ''   ${arr[@]:i:2}
}


测试结果:

Installed Products : DesktopApplicationsModule     Registered
                     ServerApplicationsModule      Registered
                     BasesystemModule              Registered
                     LegacyModule                  NotRegistered


更新,这里是sed规则/^\s*$|^-|\(.*\)|^Ins/d;s/ //g的解释。有2个sed命令,通过'分隔;第一个/.../d-删除命令和第二个s///g-替代命令。让我们仔细看看它们:

  1. /^\s*$|^-|\(.*\)|^Ins/d此命令由几个正则表达式模式组成,以匹配不需要的字符串,所有匹配的字符串将被删除:
  • ^\s*$-将匹配“空格”字符串
  • ^--将匹配从'-'开始的字符串
  • \(.*\)-将匹配带有'()'的字符串
  • ^Ins-将匹配以'Ins'开头的字符串
  1. s/ //g用空替换所有空格(删除空格)我添加了这个,因为OP在没有空格的描述中具有所需的输出。
    但是根据OP的注解空间必须保留,让我们这样做。看起来我们只需要删除第二个sed命令s/ //g?不,这会破坏输出:
Installed Products : Desktop                       Applications
                     Module                        Registered
                     Server                        Applications
                     Module                        Registered
                     Basesystem                    Module
                     Registered                    Legacy
                     Module                        Not
                     Registered


相反,我们需要将其更改(替换)为某种模式,例如_SPS_,以在数组中创建弹出项数量,然后将其更改回空格。脚本将是这样的:

# add all data to an array
arr=( $(sed -r '/^\s*$|^-|\(.*\)|^Ins/d;s/ /_SPS_/g' f) )
arr=( "${arr[@]//_SPS_/' '}" ) # change _SPS_ back to space in whole array

# print initial text and first 2 item from array
printf 'Installed Products : %-30s%s\n' "${arr[@]:0:2}"

# print the rest, loop over the rest of array
for ((i=2;i<${#arr[@]}; i+=2)); {
    # empty valued added here to propper alighnment
    printf '%21s%-30s%s\n' '' "${arr[@]:i:2}"
}


请注意,现在我将${arr[@]:i:2} Package 在"中,这是必要的,因为现在我们有了带有空格的项。下面是输出:

Installed Products :   Desktop Applications Module   Registered
                       Server Applications Module    Registered
                       Basesystem Module             Registered
                       Legacy Module                 Not Registered

aor9mmx1

aor9mmx14#

通过在sed中增加一点逻辑来缩短管道。
您不需要单独调用trgrep

sudo /usr/bin/SUSEConnect --status-text |
  sed -n '/Installed Products:/h; /Module$/H; 
          /Registered/{ H; g; s/ //g; s/\n/\t/g; p; z; x; }' |
  column --table --separator $'\t'

字符串
或者,折叠成一条更密集的单线,

sudo /usr/bin/SUSEConnect --status-text|sed -n '/Installed Products:/h; /Module$/H; /Registered/{H;g;s/ //g;s/\n/\t/g;p;z;x;}'|column -ts $'\t'


为了查看它的实际效果,我只是手动生成了示例的输出:

$: echo "
Installed Products:
------------------------------------------

  Desktop Applications Module
  (sle-module-desktop-applications/15.2/x86_64)

  Registered

------------------------------------------

  Server Applications Module
  (sle-module-server-applications/15.2/x86_64)

  Registered

------------------------------------------

  Basesystem Module
  (sle-module-basesystem/15.2/x86_64)

  Registered

------------------------------------------

  Legacy Module
  (sle-module-legacy/15.2/x86_64)

  Not Registered

" | sed -n '/Installed Products:/h; /Module$/H; 
            /Registered/{ H; g; s/ //g; s/\n/\t/g; p; z; x; }' |
    column --table --separator $'\t' 
InstalledProducts:  DesktopApplicationsModule  Registered
                    ServerApplicationsModule   Registered
                    BasesystemModule           Registered
                    LegacyModule               NotRegistered


只是有点-
-n不打印,除非我这么说。
/Installed Products:/h将这一行放入h旧缓冲区(擦除任何以前的内容)
/Module$/Hadd 这一行到H旧缓冲区
/Registered/{在这一行打开一个命令块:
H添加到H旧缓冲区
g用保持缓冲区内容替换模式缓冲区
s/ //g删除所有空格
s/\n/\t/g用制表符替换换行符
pp打印编辑的图案缓冲区
zz ap(空)模式缓冲区- *GNU特定 *
xe x change the pattern and hold buffers (empties the hold)}'关闭代码块
如果不使用GNU sed,请将z替换为s/.//g,您可能需要将所有这些命令放在不同的行上,而不是仅用分号分隔。
如果您想包含名称,请添加-E并将/Module$/H更改为/Module$|[(]/H-

sudo /usr/bin/SUSEConnect --status-text | sed -En '
  /Installed Products:/h; /Module$|[(]/H;
  /Registered/{ H; g; s/ //g; s/\n/\t/g; p; s/.//g; x; }
' | column --table --separator $'\t'
InstalledProducts:  DesktopApplicationsModule  (sle-module-desktop-applications/15.2/x86_64)  Registered
                    ServerApplicationsModule   (sle-module-server-applications/15.2/x86_64)   Registered
                    BasesystemModule           (sle-module-basesystem/15.2/x86_64)            Registered
                    LegacyModule               (sle-module-legacy/15.2/x86_64)                NotRegistered


正如Renaud指出的,使用column确实需要在输入中使用字段分隔符。在玩这个的时候,我让它使用回车(\r)和铃声字符(\a)。YMMV

相关问题