Sed 如何在目录的每个文件中用空白替换选项卡

Sed 如何在目录的每个文件中用空白替换选项卡,sed,Sed,我想用相应的空白空间替换目录中每个文件中的选项卡。我已经找到了一个解决方案11094383,在这个解决方案中,您可以在给定的空空间数的情况下用替换制表符: > find ./ -type f -exec sed -i 's/\t/ /g' {} \; 在解决方案中,上述选项卡替换为四个空格。但是在我的例子中,标签可以占据更多的空间,例如8 带有制表符的文件(应替换为8个空格)示例如下: NSMl1 100 PSHELL 0.00260 400000 40020

我想用相应的空白空间替换目录中每个文件中的选项卡。我已经找到了一个解决方案11094383,在这个解决方案中,您可以在给定的空空间数的情况下用替换制表符:

> find ./ -type f -exec sed -i 's/\t/     /g' {} \;
在解决方案中,上述选项卡替换为四个空格。但是在我的例子中,标签可以占据更多的空间,例如8

带有制表符的文件(应替换为8个空格)示例如下:

NSMl1        100  PSHELL 0.00260  400000  400200  400300
          400400  400500  400600  400700  400800  400900
      401000  401100  400100  430000  430200  430300
      430400  430500  430600  430700  430800  430900
      431000  431100  430100  401200  431200
这里带制表符的行是第3到第5行

带有选项卡的文件示例(应替换为4个选项卡)如下:

RBE2     1101001 5000511  123456    1100

有人能帮忙吗?

经典的答案是使用带有选项的
pr
命令将选项卡展开到适当数量的空格中,从而打开分页功能:

pr -e8 -l1 -t …files…
棘手的部分是将文件改写,这似乎是问题的一部分。当然,GNU和BSD(Mac OS X)版本中的
sed
支持使用
-i
选项进行覆盖,因为BSD
sed
需要备份文件的后缀,而GNU
sed
则不支持。但是,
sed
不(容易)支持将制表符转换为适当数量的空格,因此它不是完全合适的

其中有一个脚本
overwrite
(我缩写为
ow
)可以实现这一点。我从1987年开始使用这个脚本(第一次签入-最后一次更新是在2005年)

现在在大多数系统上使用
mktemp
命令是可能的,而且可以说是更好的;那时候根本不存在

在问题的上下文中,您可以使用:

find . -type f -exec ow {} pr -e8 -t -l1 \;
您确实需要单独处理每个文件

如果你真的下定决心要使用sed来完成这项工作,那么你的工作就会被裁掉。有一种可怕的方法。有一个符号问题;如何表示文字选项卡;我将使用
\t
来表示它。脚本将存储在一个文件中,我假设它是
script.sed

:again
/^\(\([^\t]\{8\}\)*\)\t/s//\1        /
/^\(\([^\t]\{8\}\)*\)\([^\t]\{1\}\)\t/s//\1\3       /
/^\(\([^\t]\{8\}\)*\)\([^\t]\{2\}\)\t/s//\1\3      /
/^\(\([^\t]\{8\}\)*\)\([^\t]\{3\}\)\t/s//\1\3     /
/^\(\([^\t]\{8\}\)*\)\([^\t]\{4\}\)\t/s//\1\3    /
/^\(\([^\t]\{8\}\)*\)\([^\t]\{5\}\)\t/s//\1\3   /
/^\(\([^\t]\{8\}\)*\)\([^\t]\{6\}\)\t/s//\1\3  /
/^\(\([^\t]\{8\}\)*\)\([^\t]\{7\}\)\t/s//\1\3 /
t again
这是使用经典的
sed
表示法

然后你可以写:

sed -f script.sed …data-files…
如果您有GNU
sed
或BSD(Mac OS X)
sed
,则可以改用扩展正则表达式:

:again
/^(([^\t]{8})*)\t/s//\1        /
/^(([^\t]{8})*)([^\t]{1})\t/s//\1\3       /
/^(([^\t]{8})*)([^\t]{2})\t/s//\1\3      /
/^(([^\t]{8})*)([^\t]{3})\t/s//\1\3     /
/^(([^\t]{8})*)([^\t]{4})\t/s//\1\3    /
/^(([^\t]{8})*)([^\t]{5})\t/s//\1\3   /
/^(([^\t]{8})*)([^\t]{6})\t/s//\1\3  /
/^(([^\t]{8})*)([^\t]{7})\t/s//\1\3 /
t again
然后运行:

sed -r -f script.sed …data-files…    # GNU sed
sed -E -f script.sed …data-files…    # BSD sed
脚本是做什么的

第一行设置标签;如果中间的任何
s//
操作进行了替换,则最后一行跳转到该标签。因此,对于文件的每一行,脚本都会循环,直到没有匹配为止,因此不会执行替换

8次替换涉及:

  • 由8个非制表符组成的零个或多个序列组成的块,该块被捕获,后跟
  • 还有0-7个非制表符,也会被捕获,然后是
  • 账单
  • 它将使用捕获的材质替换该匹配,然后使用适当数量的空格
在测试过程中发现的一个奇怪现象是,如果一行以空格结尾,则
pr
命令会删除该尾随空格

在某些系统(至少是BSD或Mac OS X)上还有
expand
命令,它保留了后面的空白。使用它比
pr
sed
更简单

使用这些
sed
脚本,并将BSD或GNU
sed
与备份文件一起使用,您可以编写:

find . -type f -exec sed -i.bak -r -f script.sed {} +

(GNU
sed
表示法;用
-E
代替
-r
代替BSD
sed

你想用6或8个空格代替制表符吗?在我的例子中,我必须用4、6或8个空格代替制表符你正在寻找的
扩展
:它会用8个空格代替制表符<代码>查找。/-type f-exec sed-i's/\t/\s\{8\}/g'{}请提供一些示例输入供我们使用。
find . -type f -exec sed -i.bak -r -f script.sed {} +