unix - команда cut (добавление собственного разделителя) - PullRequest
3 голосов
/ 25 декабря 2011

Имеется файл с такими данными (например, файл stores.dat)

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

Желаемый вывод:

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

Хотелось бы добавить "|" Разделитель между каждым из этих трех диапазонов среза:

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

Каков синтаксис для вставки разделителя между каждым вырезом?

BONUS pts (если вы можете предоставить возможность обрезать значения следующим образом):

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

ОБНОВЛЕНИЕ (благодаря ответу Мата) Я закончил с успехом в этом решении - (это немного грязно, но SunOS с моей версией bash, похоже, не поддерживает более элегантную арифметику)

#!/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

Ответы [ 7 ]

6 голосов
/ 26 декабря 2011

Так как вы использовали cut в вашем примере. Предполагая, что каждое поле отделено вкладкой:

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

если это не так, добавить переключатель входного-разделителя -d

4 голосов
/ 25 декабря 2011

Я бы использовал awk:

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

Как и некоторые другие предложения, он предполагает, что столбцы разделены пробелами, и не заботится о номерах столбцов.Если у вас есть пробелы в одном из полей, оно не будет работать.

2 голосов
/ 14 августа 2014

Лучшее решение 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
1 голос
/ 25 декабря 2011

Если вы не боитесь использовать 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.

0 голосов
/ 25 декабря 2011

Как насчет использования команды 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

Примечание. Как отметил Мэт в комментариях, это решение предполагает, что каждый столбец отделен одним или несколькими пробелами и не разделен фиксированной длиной.

0 голосов
/ 25 декабря 2011

Насколько я знаю, вы не можете сделать это с помощью cut, но вы можете легко сделать это с помощью sed, если значения в каждом столбце никогда не имеют внутренних пробелов:

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

РЕДАКТИРОВАТЬ: Если формат файла является истинным форматом с фиксированным столбцом, и вы не хотите использовать perl, как показано Mat, это может быть сделано с sed, но это не так довольно, потому что sed не поддерживает числовые квантификаторы повторения (.{17}), поэтому вы должны ввести правильное количество точек:

sed -e 's/^\(.................\)\(............\)\(..........\)$/\1|\2|\3/; s/  *|/|/g'
0 голосов
/ 25 декабря 2011

используйте 'sed' для поиска и замены частей файла на основе регулярных выражений

Замените пробел на '|'из infile1

sed -e 's/[ \t\r]/|/g' infile1 > outfile3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...