Unix - cut命令(添加自己的分隔符)



给定一个包含如下数据的文件(即stores.dat文件)

id               storeNo     type
2ttfgdhdfgh      1gfdkl-28   kgdl
9dhfdhfdfh       2t-33gdm    dgjkfndkgf
所需输出:

id               |storeNo     |type
2ttfgdhdfgh      |1gfdkl-28   |kgdl
9dhfdhfdfh       |2t-33gdm    |dgjkfndkgf

想要在这3个截断范围之间添加一个"|"分隔符:

cut -c1-18,19-30,31-40 stores.dat

在每个切口之间插入分隔符的语法是什么?

额外分数(如果你能提供这样的选项来修剪值):

id|storeNo|type
2ttfgdhdfgh|1gfdkl-28|kgdl
9dhfdhfdfh|2t-33gdm|dgjkfndkgf

UPDATE(感谢Mat的回答)我最终在这个解决方案上取得了成功-(它有点混乱,但是我的bash版本的SunOS似乎不支持更优雅的算法)

#!/bin/bash
unpack=""
filename="$1"
while [ $# -gt 0 ] ; do
    arg="$1"
    if [ "$arg" != "$filename" ]
    then
        firstcharpos=`echo $arg | awk -F"-" '{print $1}'`
        secondcharpos=`echo $arg | awk -F"-" '{print $2}'`
        compute=`(expr $firstcharpos - $secondcharpos)`
        compute=`(expr $compute * -1 + 1)`
        unpack=$unpack"A"$compute
    fi
    shift
done
perl -ne 'print join("|",unpack("'$unpack'", $_)), "n";' $filename 

用法:sh test.sh input_file 1-17 18-29 30-39

因为您在示例中使用了cut。假设每个字段用制表符分隔:

$ cut  --output-delimiter='|' -f1-3 input
id|store|No
2ttfgdhdfgh|1gfdkl-28|kgdl
9dhfdhfdfh|2t-33gdm|dgjkfndkgf

如果不是这样,则添加输入分隔符开关-d

我会使用awk:

awk '{print $1 "|" $2 "|" $3}'

与其他一些建议一样,它假设列是用空格分隔的,并且不关心列号。

如果其中一个字段中有空格,则无法工作。

基于字符位置而不是空白的更好的awk解决方案

$ awk -v FIELDWIDTHS='17 12 10' -v OFS='|' '{ $1=$1 ""; print }' stores.dat | tr -d ' '
id|storeNo|type
2ttfgdhdfgh|1gfdkl-28|kgdl
9dhfdhfdfh|2t-33gdm|dgjkfndkgf

如果您不害怕使用perl,这里有一个一行代码:

$ perl -ne 'print join("|",unpack("A17A12A10", $_)), "n";' input 

unpack调用将从输入行提取一个17个字符的字符串,然后是一个12个字符的字符串,然后是一个10个字符的字符串,并将它们返回到数组中(去掉空格)。join| s

如果您希望输入列是x-y格式,而不编写"真正的"脚本,您可以像这样修改它(但它很丑):

#!/bin/bash
unpack=""
while [ $# -gt 1 ] ; do
    arg=$(($1))
    shift
    unpack=$unpack"A"$((-1*$arg+1))
done
perl -ne 'print join("|",unpack("'$unpack'", $_)), "n";' $1 

用法:t.sh 1-17 18-29 30-39 input_file .

据我所知,你不能用cut做到这一点,但你可以很容易地用sed做到这一点,只要每列的值从来没有内部空间:

sed -e 's/  */|/g'

编辑:如果文件格式是真正的固定列格式,并且您不想使用Mat所示的perl,则此可以用sed完成,但它不是很漂亮,因为sed不支持数字重复量词(.{17}),因此您必须键入正确的点数:

sed -e 's/^(.................)(............)(..........)$/1|2|3/; s/  *|/|/g'

只使用tr命令如何?

tr -s " " "|" < stores.dat

摘自man页:

-s      Squeeze multiple occurrences of the characters listed in the last
        operand (either string1 or string2) in the input into a single
        instance of the character.  This occurs after all deletion and
        translation is completed.

测试:

[jaypal:~/Temp] cat stores.dat 
id               storeNo     type
2ttfgdhdfgh      1gfdkl-28   kgdl
9dhfdhfdfh       2t-33gdm    dgjkfndkgf
[jaypal:~/Temp] tr -s " " "|" < stores.dat 
id|storeNo|type
2ttfgdhdfgh|1gfdkl-28|kgdl
9dhfdhfdfh|2t-33gdm|dgjkfndkgf

你可以很容易地重定向到一个新的文件,像这样-

[jaypal:~/Temp] tr -s " " "|" < stores.dat > new.stores.dat

您可以简单地使用

cat stores.dat | tr -s ' ' '|'

使用'sed'根据正则表达式搜索和替换文件的部分内容

将infile1中的空格替换为'|'

sed -e 's/[ tr]/|/g' infile1 > outfile3

最新更新