/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 有子卷可以使用subvol
和subvolid
安装选项单独安装。
这也意味着第一列中的设备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
与sed
和nl
:
nl -ba -nrz -s: /etc/fstab | \
sed '/^[[:digit:]]*:[[:blank:]]*\(#\|$\)/d;//!{s/\\/&&/g}' | \
column -t | sed 's|^0*\([[:digit:]]*\):\(.\)|\1c\\\
\2|' | sed -f - /etc/fstab
或与sed
和grep
:
grep -nvE '^[[:blank:]]*(#|$)' /etc/fstab | \
sed -E 's/\\/&&/g;s/^([[:digit:]])*:(.*)/\1c\\\
\2/' | column -t | sed -f - /etc/fstab
或者更短,带有sed
和awk
:
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
命令分为file0
,file1
带注释的行和file2
,不带注释的行。 (XX*
方法X
后跟零个或多个X
s;换句话说;一个或多个X
s.这是“穷人的版本” 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 工具的系统)。 放弃
file1
andfile2
并将最后一行压缩为类似的内容(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