如何使“column -t”忽略具有特定特征的行?

如何使“column -t”忽略具有特定特征的行?

/etc/fstab我只是想通过管道column -te获得一个格式良好的表格该有多好。
column当然无法识别注释行和挂载点定义,因此注释也会在每个空格处分割并格式化为表列:

#                                          /etc/fstab:                  static   file                                      system     information.
#
#                                          Use                          'blkid'  to                                        print      the           universally   unique      identifier  for       a
#                                          device;                      this     may                                       be         used          with          UUID=       as          a         more  robust     way  to  name  devices
#                                          that                         works    even                                      if         disks         are           added       and         removed.  See   fstab(5).
#
#                                          <file                        system>  <mount                                    point>     <type>        <options>     <dump>      <pass>

#                                          /                            was      on                                        /dev/sda2  during        installation
UUID=8fa99d69-8dac-4aca-bb61-90f753ba5169  /                            btrfs    defaults,subvol=@rootfs,metadata_ratio=6  0          1
#                                          /home                        was      on                                        /dev/sda2  during        installation
UUID=8fa99d69-8dac-4aca-bb61-90f753ba5169  /home                        btrfs    defaults,subvol=@home                     0          2

有没有办法column只制作不以 开头的格式行#


编辑:看来我需要澄清上面的例子实际上是一个有效的fstab. Btrfs 有子卷可以使用subvolsubvolid安装选项单独安装。
这也意味着第一列中的设备fstab不一定是唯一的。

答案1

我认为务实的解决方案是让column整个文件发挥作用,然后简单地折叠注释行中的任何多个空格

column -t /etc/fstab | sed '/^#/ s/ \{1,\}/ /g'

否则,除了对行进行编号、分别处理注释行和非注释行,然后将它们全部粘在一起之外,我看不到任何方法可以做到这一点,例如

sort -nk1,1 \
<(nl -nln /etc/fstab | grep -vE '^[[:digit:]]+[[:space:]]+#'| column -t | sed 's/ \{1,\}/\t/') \
<(nl -nln /etc/fstab | grep -E '^[[:digit:]]+[[:space:]]+#') \
| cut -f2-

答案2

sednl

nl -ba -nrz -s: /etc/fstab | \
sed '/^[[:digit:]]*:[[:blank:]]*\(#\|$\)/d;//!{s/\\/&&/g}' | \
column -t | sed 's|^0*\([[:digit:]]*\):\(.\)|\1c\\\
\2|' | sed -f - /etc/fstab

或与sedgrep

grep -nvE '^[[:blank:]]*(#|$)' /etc/fstab | \
sed -E 's/\\/&&/g;s/^([[:digit:]])*:(.*)/\1c\\\
\2/' | column -t | sed -f - /etc/fstab

或者更短,带有sedawk

awk '!/^[[:blank:]]*(#|$)/{print NR"c\\";gsub(/\\/,"&&");print}' \
/etc/fstab | column -t | sed -f - /etc/fstab

使用测试文件:

# /etc/fstab: static file system information
# <file system> <dir>   <type>  <options>   <dump>  <pass>

LABEL=ROOT    / ext4 noatime,discard 0 1
UUID=8fa99d69-8dac-4aca-bb61-90f753ba5169  / btrfs  defaults,subvol=@rootfs,metadata_ratio=6 0  1
# /home was on /dev/sda2  during installation
UUID=8fa99d69-8dac-4aca-bb61-90f753ba5169  /home btrfs  defaults,subvol=@home  0 2
LABEL=SWAP   none  swap sw,discard  0 0
UUID=7fa3-cb08  /media ext4 defaults 0 0

输出是:

# /etc/fstab: static file system information
# <file system> <dir>   <type>  <options>   <dump>  <pass>

LABEL=ROOT                                 /       ext4   noatime,discard                           0  1
UUID=8fa99d69-8dac-4aca-bb61-90f753ba5169  /       btrfs  defaults,subvol=@rootfs,metadata_ratio=6  0  1
# /home was on /dev/sda2  during installation
UUID=8fa99d69-8dac-4aca-bb61-90f753ba5169  /home   btrfs  defaults,subvol=@home                     0  2
LABEL=SWAP                                 none    swap   sw,discard                                0  0
UUID=7fa3-cb08                             /media  ext4   defaults                                  0  0

它们是如何工作的:
最后一个使用由前面的命令生成的脚本文件(从中读取)sed -f - /etc/fstab仅修改挂载点定义/etc/fstab(保留其他行 - 包括空行 - 不变) :f-stdin

4c\
LABEL=ROOT                                 /       ext4   noatime,discard                           0  1
5c\
UUID=8fa99d69-8dac-4aca-bb61-90f753ba5169  /       btrfs  defaults,subvol=@rootfs,metadata_ratio=6  0  1
7c\
UUID=8fa99d69-8dac-4aca-bb61-90f753ba5169  /home   btrfs  defaults,subvol=@home                     0  2
8c\
LABEL=SWAP                                 none    swap   sw,discard                                0  0
9c\
UUID=7fa3-cb08                             /media  ext4   defaults                                  0  0

第一个用于nl -ba -nrz -s:对所有行进行编号

sed '/^[[:digit:]]*:[[:blank:]]*\(#\|$\)/d;//!{s/\\/&&/g}'

删除最初注释或空的行,并转义剩余行中的任何反斜杠(我知道在这种特殊情况下不需要),然后将输出通过管道传输到,column -t以便只列出挂载点定义:

000004:LABEL=ROOT                                 /       ext4   noatime,discard                           0  1
000005:UUID=8fa99d69-8dac-4aca-bb61-90f753ba5169  /       btrfs  defaults,subvol=@rootfs,metadata_ratio=6  0  1
000007:UUID=8fa99d69-8dac-4aca-bb61-90f753ba5169  /home   btrfs  defaults,subvol=@home                     0  2
000008:LABEL=SWAP                                 none    swap   sw,discard                                0  0
000009:UUID=7fa3-cb08                             /media  ext4   defaults                                  0  0

这进一步处理

sed 's|^0*\([[:digit:]]*\):\(.\)|\1c\\\
\2|'

生成上述脚本文件。
第二个和第三个是相似的(它们产生相同的输出),所以要么

grep -nvE '^[[:blank:]]*(#|$)' | sed -E 's/\\/&&/g;s/^([[:digit:]])*:(.*)/\1c\\\
\2/'

或者

awk '!/^[[:blank:]]*(#|$)/{print NR"c\\";gsub(/\\/,"&&");print}'

将仅匹配安装点定义,转义反斜杠(如果有),打印行号,后跟c\和(在单独的行上)实际行内容:

4c\
LABEL=ROOT    / ext4 noatime,discard 0 1
5c\
UUID=8fa99d69-8dac-4aca-bb61-90f753ba5169  / btrfs  defaults,subvol=@rootfs,metadata_ratio=6 0  1
7c\
UUID=8fa99d69-8dac-4aca-bb61-90f753ba5169  /home btrfs  defaults,subvol=@home  0 2
8c\
LABEL=SWAP   none  swap sw,discard  0 0
9c\
UUID=7fa3-cb08  /media ext4 defaults 0 0

然后通过管道传输到column -t生成相同的脚本文件。


另一种方法与ed此相同,但仅读取文件一次:

ed -s <<IN <(nl -ba -nrz -s: /etc/fstab) | sort -t: -k1,1 | cut -d: -f2-
g/^[[:digit:]]*:[[:blank:]]*\(#\|$\)/p
g//d
,w !column -t
q
IN

编号的行用作 的输入ed,第一个子命令p打印所有最初注释或空的行 ( g),第二个子命令d删除它们,然后将剩余的行作为输入 () 传递w给 shell( !) 命令column -t。整个输出被sort编辑并cut删除前导数字。

答案3

建议“在提供给 之前删除评论怎么样column?”也不是完全没有优点。

#!/bin/sh
nl -ba /etc/fstab | sed "s/^ *//; s/\t/ /" > file0
grep    "^[0-9][0-9]* #" file0 > file1
grep -v "^[0-9][0-9]* #" file0 > file2
(cat file1; column -t file2) | sort -n | sed "s/^[0-9][0-9]* *//"

nl –ba每行编号;格式实际上是%6d\t;即,一个带有前导空格的数字,后跟一个制表符。  sed "s/^ *//; s/\t/ /"去掉前导空格并用空格替换制表符,使其看起来更像column输出的样子。这些grep命令分为file0file1带注释的行和file2,不带注释的行。 (XX* 方法X后跟零个或多个Xs;换句话说;一个或多个Xs.这是“穷人的版本” X+;即,一种以可移植/通用的方式表示一个或多个 s 的方式X。)每个文件都保留行号从原始/etc/fstab文件

(cat file1; column -t file2)通过 运行非注释行column –t,将结果连接到注释行(其水平间距未修改)。然后sort –n将行恢复到原来的顺序,并sed "s/^[0-9][0-9]* *//"去掉行号。

输出:

# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>

# / was on /dev/sda2 during installation
UUID=8fa99d69-8dac-4aca-bb61-90f753ba5169  /      btrfs  defaults,subvol=@rootfs,metadata_ratio=6  0  1
# /home was on /dev/sda2 during installation
UUID=8fa99d69-8dac-4aca-bb61-90f753ba5169  /home  btrfs  defaults,subvol=@home                     0  2

请注意,这支持空白行和带有嵌入空格的注释行(即嵌入制表符或两个或多个空格的字符串),但不支持缩进行(即,领导制表符或空格)。

如果您想稍微强化此脚本(即,使其更像生产版本),您可以

  • 将临时文件替换为/tmp具有随机 ( mktemp) 生成名称的文件。
  • 完成后删除临时文件。
  • 在适当的地方更改为使用[0-9]+(如果您的系统太旧,这可能不适用于您;例如,Solaris、AIX 或任何没有 GNU 工具的系统)。
  • 放弃file1andfile2并将最后一行压缩为类似的内容

    (grep "^[0-9][0-9]* #" file0; grep -v "^[0-9][0-9]* #" file0 | column -t) | …
    

    但我认为最好多写几行并且更清楚。

  • 添加对缩进线的支持。

答案4

我认为你不能单独用专栏来做到这一点..编写一个简单的脚本来做到这一点并不太困难。

编辑:这可能有效,而且要短一些。我在上面的原始示例中尝试过它,尽管它已经通过专栏。我确实注意到这会删除空行,所以如果这是一个问题,它可能仍然需要一些抛光。

#!/bin/bash

INPUTFILE="${1}"

IFS=$'\r\n' GLOBIGNORE='*';
COMMENTS=(`grep -n ^# "${INPUTFILE}"`) 
ENTRIES=(`grep -n -v ^# "${INPUTFILE}" | column -t`)
TMPTAB=(`printf "%s\n" ${ENTRIES[@]} && printf "%s\n" ${COMMENTS[@]}`)

NEWTAB=(`printf "%s\n" ${TMPTAB[@]} | sort -n -t: -k1 | sed 's/^[0-9]\+://'`)
printf "%s\n" ${NEWTAB[@]}

我将在这里留下我原来的答案,但正如 @scott 指出的那样,它不适用于某些有效的 fstab。

#!/bin/bash 

# columnize the non-comment lines
TABS=`grep -v ^# /etc/fstab | column -te`

# read the original fstab
while read LINE
 do 
  echo "${LINE}" | grep ^# > /dev/null 

  # if it is a comment line just write it in
  if [ $? -eq 0 ]
  then
       echo "${LINE}" >> new.fstab
  else
    # otherwise get the matching entry from the columnized fstab 
    ENTRY=`echo "${LINE}" | awk '{ print $1 }'`
    echo "${TABS}" | grep ^"${ENTRY}" >> new.fstab
  fi
 done < /etc/fstab

相关内容