Удалить поле по позиции из длинной строки - PullRequest
6 голосов
/ 27 марта 2012

У меня длинная строка полей, разделенных точкой с запятой, 69, если быть точным.

Мне нужно удалить поле 3, чтобы я мог, более подробно, сделать:

awk -F\; '$1 == 3 { print $1";"$2";"$4 ... }' a.txt

Что будет очень долго. Есть ли ярлык «4 до конца», «от 4 до 69» или просто «удалить 3»?

Относится к вопросу: повторение ";" повсюду очень неудобно.

Конечно, я мог бы сгенерировать команду частично с:

echo -e "\b"{4..69}"\";\"$"

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

Что такое элегантное решение - желательно в чистом виде

Полагаю, я могу быстро найти sed-решение, но у меня есть еще кое-что сделать (пересчитать Поле 5: если Поле 1 == 2, Поле 5 = 5-Поле 5), что будет сложно в sed, но я думаю, хорошо подходит для awk.

Я использую Gnu-AWK 3.1.6, если это имеет значение, но имеет, в соответствии с:

  • AWK
  • простак
  • igawk
  • Мок
  • nawk
  • pgawk

ок, обновление:

Я должен был знать лучше и сразу предоставить некоторые тестовые данные, но, конечно, я опробую все ваши ответы и опишу то, что выглядит многообещающе.

3;03.2012;7228;0;1;3;1;3;4;3;1;3;4;3;2;0;4;4;1;1;4;2;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;3;0;3;1;3;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;
3;03.2012;7229;0;2;2;0;5;5;4;4;5;5;4;4;2;5;5;0;0;3;3;0;0;5;6;0;0;0;0;0;2;2;1;2;1;2;2;2;4;3;4;1;5;4;2;0;0;0;0;0;0;0;0;0;0;4;4;4;4;4;0;0;0;0;0;0;0;
3;03.2012;7230;0;2;2;2;4;3;4;4;4;3;3;3;2;4;6;1;1;1;6;5;1;6;6;1;1;1;1;1;2;2;1;2;2;0;2;2;3;4;2;1;4;3;2;0;0;0;0;0;0;0;0;0;0;4;3;3;4;4;0;0;0;0;0;0;0;
3;03.2012;7231;0;1;3;1;4;4;3;3;4;4;4;4;2;5;5;1;1;4;6;5;1;4;1;1;1;1;1;5;2;1;1;2;0;0;1;2;4;4;3;1;4;3;2;0;0;0;0;0;0;0;0;0;0;4;4;4;4;3;0;0;0;0;0;0;0;

просто держи линию. :)

Ответы [ 8 ]

5 голосов
/ 27 марта 2012

Мне не жаль прерывать эту извращенную игру в гольф. Вам, мазохистам, нравится изобретать велосипед? Civilization предлагает современному человеку такие удобства, как сбор сточных вод и библиотеки CSV, поэтому ему не приходится иметь дело с

Как насчет csvfix ? Это инструмент командной строки, который работает с потоком текста, т.е. та же среда, что и в awk. Вам нужна команда exclude

csvfix exclude -f 3 -rsep ";" a.txt
3 голосов
/ 27 марта 2012

В одну сторону:

awk '{ 
  split( $0, f, /;/ );
  delete f[3];
  for (i=1; i<=length(f); i++) { 
    printf "%s", f[i] ? f[i] ";" : "" 
  } 
}' <<<"one;two;three;four;five;six;seven"

Со следующим выводом:

one;two;four;five;six;seven;
2 голосов
/ 27 марта 2012

Вместо этого вы можете использовать команду cut:

cut -d';' -f1,2,4- a.txt

Список полей может быть диапазоном и может включать открытый диапазон (например, 4 - используется здесь)

И если вам все еще нужно обработать результат в awk, вы можете передать вывод из него в него.

1 голос
/ 29 марта 2012
awk -F";" 'BEGIN{OFS=";"} {$3="";print }' file3|sed 's/;;/;/'

вот тест:

pearl.341> cat file3
3;03.2012;7228;0;1;3;1;3;4;3;1;3;4;3;2;0;4;4;1;1;4;2;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;3;0;3;1;3;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;
3;03.2012;7229;0;2;2;0;5;5;4;4;5;5;4;4;2;5;5;0;0;3;3;0;0;5;6;0;0;0;0;0;2;2;1;2;1;2;2;2;4;3;4;1;5;4;2;0;0;0;0;0;0;0;0;0;0;4;4;4;4;4;0;0;0;0;0;0;0;
3;03.2012;7230;0;2;2;2;4;3;4;4;4;3;3;3;2;4;6;1;1;1;6;5;1;6;6;1;1;1;1;1;2;2;1;2;2;0;2;2;3;4;2;1;4;3;2;0;0;0;0;0;0;0;0;0;0;4;3;3;4;4;0;0;0;0;0;0;0;
3;03.2012;7231;0;1;3;1;4;4;3;3;4;4;4;4;2;5;5;1;1;4;6;5;1;4;1;1;1;1;1;5;2;1;1;2;0;0;1;2;4;4;3;1;4;3;2;0;0;0;0;0;0;0;0;0;0;4;4;4;4;3;0;0;0;0;0;0;0;

Выход:

pearl.342> awk -F";" 'BEGIN{OFS=";"} {$3="";print }' file3 | sed 's/;;/;/'
3;03.2012;0;1;3;1;3;4;3;1;3;4;3;2;0;4;4;1;1;4;2;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;3;0;3;1;3;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;
3;03.2012;0;2;2;0;5;5;4;4;5;5;4;4;2;5;5;0;0;3;3;0;0;5;6;0;0;0;0;0;2;2;1;2;1;2;2;2;4;3;4;1;5;4;2;0;0;0;0;0;0;0;0;0;0;4;4;4;4;4;0;0;0;0;0;0;0;
3;03.2012;0;2;2;2;4;3;4;4;4;3;3;3;2;4;6;1;1;1;6;5;1;6;6;1;1;1;1;1;2;2;1;2;2;0;2;2;3;4;2;1;4;3;2;0;0;0;0;0;0;0;0;0;0;4;3;3;4;4;0;0;0;0;0;0;0;
3;03.2012;0;1;3;1;4;4;3;3;4;4;4;4;2;5;5;1;1;4;6;5;1;4;1;1;1;1;1;5;2;1;1;2;0;0;1;2;4;4;3;1;4;3;2;0;0;0;0;0;0;0;0;0;0;4;4;4;4;3;0;0;0;0;0;0;0;
1 голос
/ 28 марта 2012

Pure Bash:

IFS=';'
while read -a line ; do
  unset line[2]
  echo "${line[*]}"
done < infile.dat
1 голос
/ 27 марта 2012

Вы можете использовать что-то вроде этого:

awk -v fl=<filed_list> 'BEGIN {
  n = split(fl, t, " ")
  for (i = 0; ++i <= n;)
    fa[t[i]]
  }
{
  for (i = 0; ++i <= NF;)
    if (!(i in fa))
      printf "%s", ($i (i < NF ? OFS : ORS))
  }' 

Рассмотрим следующий ввод:

zsh-4.3.14[t]% paste -sd\; < <(printf '%s\n' {1..10})
1;2;3;4;5;6;7;8;9;10

Для удаления 3-го поля:

zsh-4.3.14[t]% paste -sd\; < <(printf '%s\n' {1..10}) |
pipe>   awk -F\; -v fl=3 'BEGIN {
pipe quote>     n = split(fl, t, " ")
pipe quote>     for (i = 0; ++i <= n;)
pipe quote>       fa[t[i]]
pipe quote>     }
pipe quote>   {
pipe quote>     for (i = 0; ++i <= NF;)
pipe quote>       if (!(i in fa))
pipe quote>     printf "%s", ($i (i < NF ? OFS : ORS))
pipe quote>   }' OFS=\;
1;2;4;5;6;7;8;9;10

Чтобы удалить набор полей:

zsh-4.3.14[t]% paste -sd\; < <(printf '%s\n' {1..10}) |
pipe>   awk -F\; -v fl='7 4 3' 'BEGIN {
pipe quote>     n = split(fl, t, " ")
pipe quote>     for (i = 0; ++i <= n;)
pipe quote>       fa[t[i]]
pipe quote>     }
pipe quote>   {
pipe quote>     for (i = 0; ++i <= NF;)
pipe quote>       if (!(i in fa))
pipe quote>     printf "%s", ($i (i < NF ? OFS : ORS))
pipe quote>   }' OFS=\;
1;2;5;6;8;9;10

Дайте мне знать, как должен выглядеть вывод, если вы удалите последнее поле (с или без конечного ФС).

Учтите, что с односимвольным разделителем полей и для простых задач cut может быть достаточно:

zsh-4.3.14[t]% paste -sd\; < <(printf '%s\n' {1..10}) | cut -d\; -f 1-2,4-
1;2;4;5;6;7;8;9;10
zsh-4.3.14[t]% paste -sd\; < <(printf '%s\n' {1..10}) | cut -d\; -f 1-2,5-6,8-
1;2;5;6;8;9;10

[Редактировать: следуя комментариям здесь]

Учитывая пример ввода:

3;03.2012;7228;0;1;3;1;3;4;3;1;3;4;3;2;0;4;4;1;1;4;2;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;3;0;3;1;3;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;
3;03.2012;7229;0;2;2;0;5;5;4;4;5;5;4;4;2;5;5;0;0;3;3;0;0;5;6;0;0;0;0;0;2;2;1;2;1;2;2;2;4;3;4;1;5;4;2;0;0;0;0;0;0;0;0;0;0;4;4;4;4;4;0;0;0;0;0;0;0;
3;03.2012;7230;0;2;2;2;4;3;4;4;4;3;3;3;2;4;6;1;1;1;6;5;1;6;6;1;1;1;1;1;2;2;1;2;2;0;2;2;3;4;2;1;4;3;2;0;0;0;0;0;0;0;0;0;0;4;3;3;4;4;0;0;0;0;0;0;0;
3;03.2012;7231;0;1;3;1;4;4;3;3;4;4;4;4;2;5;5;1;1;4;6;5;1;4;1;1;1;1;1;5;2;1;1;2;0;0;1;2;4;4;3;1;4;3;2;0;0;0;0;0;0;0;0;0;0;4;4;4;4;3;0;0;0;0;0;0;0;

и следующий awk скрипт:

zsh-4.3.14[t]% cat s.awk 
BEGIN {
  n = split(fl, t, " ")
  for (i = 0; ++i <= n;)
    fa[t[i]]
  }
{
  for (i = 0; ++i <= NF;)
    if (!(i in fa))
      printf "%s", ($i (i < NF ? OFS : ORS))
  } 

С помощью этой команды:

zsh-4.3.14[t]% awk -F\; -v fl=3 -f s.awk OFS=\; infile > outfile

... Я получаю следующий вывод:

zsh-4.3.14[t]% cat outfile
3;03.2012;0;1;3;1;3;4;3;1;3;4;3;2;0;4;4;1;1;4;2;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;3;0;3;1;3;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;
3;03.2012;0;2;2;0;5;5;4;4;5;5;4;4;2;5;5;0;0;3;3;0;0;5;6;0;0;0;0;0;2;2;1;2;1;2;2;2;4;3;4;1;5;4;2;0;0;0;0;0;0;0;0;0;0;4;4;4;4;4;0;0;0;0;0;0;0;
3;03.2012;0;2;2;2;4;3;4;4;4;3;3;3;2;4;6;1;1;1;6;5;1;6;6;1;1;1;1;1;2;2;1;2;2;0;2;2;3;4;2;1;4;3;2;0;0;0;0;0;0;0;0;0;0;4;3;3;4;4;0;0;0;0;0;0;0;
3;03.2012;0;1;3;1;4;4;3;3;4;4;4;4;2;5;5;1;1;4;6;5;1;4;1;1;1;1;1;5;2;1;1;2;0;0;1;2;4;4;3;1;4;3;2;0;0;0;0;0;0;0;0;0;0;4;4;4;4;3;0;0;0;0;0;0;0;

Если я правильно понимаю требование, вывод верен.

Для удаления полей с 1 по 5:

zsh-4.3.14[t]% awk -F\; -v fl='1 2 3 4 5' -f s.awk OFS=\; infile > outfile
zsh-4.3.14[t]% cat outfile
3;1;3;4;3;1;3;4;3;2;0;4;4;1;1;4;2;1;1;1;1;1;1;1;1;1;1;1;1;0;0;0;1;1;3;0;3;1;3;0;1;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;
2;0;5;5;4;4;5;5;4;4;2;5;5;0;0;3;3;0;0;5;6;0;0;0;0;0;2;2;1;2;1;2;2;2;4;3;4;1;5;4;2;0;0;0;0;0;0;0;0;0;0;4;4;4;4;4;0;0;0;0;0;0;0;
2;2;4;3;4;4;4;3;3;3;2;4;6;1;1;1;6;5;1;6;6;1;1;1;1;1;2;2;1;2;2;0;2;2;3;4;2;1;4;3;2;0;0;0;0;0;0;0;0;0;0;4;3;3;4;4;0;0;0;0;0;0;0;
3;1;4;4;3;3;4;4;4;4;2;5;5;1;1;4;6;5;1;4;1;1;1;1;1;5;2;1;1;2;0;0;1;2;4;4;3;1;4;3;2;0;0;0;0;0;0;0;0;0;0;4;4;4;4;3;0;0;0;0;0;0;0;

Я что-то упустил?

0 голосов
/ 28 марта 2012

Во время тестирования я сам нашел (как объявлено) решение для sed:

sed -r 's/(([^;]*;){3}).;(.*)/\1\3/' a.txt > g.txt

Не легко прочитать, но легко написать, если вы знаете sed.Похоже, что я иду с 2 решениями для моей проблемы: удалить с одной программой, и преобразовать с другой.

Удаляет поле 3 (если мы посчитаем от 0, а не от 1) :).

0 голосов
/ 27 марта 2012

Мне нужно удалить поле 3 ... Есть ли ярлык, чтобы сказать '$ 4 до конца'

Да, и он в основном спрашивает то же самоекак этот вопрос Печать поля 'N' до конца строки

awk -F\; '{print $1 FS $2 FS substr($0, index($0, $4))}' temp.txt

Это также обрабатывает бонусный вопрос

FS это полеразделитель, так что вывод из моего файла 7 полей, разделенных ';'будет выглядеть следующим образом:

awk -F \;'{print $ 1 FS $ 2 FS substr ($ 0, индекс ($ 0, $ 4))}' temp2

$> поле1; поле2; поле4; поле5; поле6; поле7

примечание: , что поле печати N до конца сохраняет разделитель полей естественным образом - по крайней мере, насколько я понимаю

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...