удалить строки в файле csv старше 7 дней

У меня есть csv, что мне нужно удалить все строки, которые старше 7 дней. Это формат csv

 Идентификатор личности VIP CS SS LT FTLT PS Измененная дата
 T001028 1 1 1 0 0 0 05-07-2013
 T001250 1 1 1 0 0 0 08-05-2012
 T001261 ​​1 1 1 0 0 1 04-04-2013
 T001345 1 1 1 0 0 0 04-03-2013
 T078503 1 1 1 0 0 0 04-03-2013
 T079819 1 1 1 0 0 1 23.02.2013
 T080119 1 1 1 0 0 1 04-02-2013
 T090574 1 1 1 0 0 0 11/15/2012
 T091106 1 1 1 0 0 1 23.02.2013

Формат столбца Дата изменения – MM / DD / YYYY – Любые идеи … нужно искать что-то в окне RedHat 5 linux.

5 Solutions collect form web for “удалить строки в файле csv старше 7 дней”

Вот метод, использующий tail , date -d ... , awk и просто функциональность Bash.

 tail -n+2 file.csv | { while read line ; do tmstmp=$(echo "$line" | awk '{print $8}'); [ $(( $(date -d "now" +%s) - $(date -d "$tmstmp" +%s) )) -lt $(( 60*60*24*7 )) ] && echo "$line"; done; } 

Как это работает?

Вышеописанное анализирует строки из файла file.csv и получает 8-й столбец (дата), а затем вычисляет дельта между количеством секунд, прошедших с момента времени, и синтаксической датой. Если у них меньше секунд на 7 дней, тогда строка будет напечатана.

отладка

Вы можете включить эту строку для отладки, что происходит. Поместите его сразу после tmpstmp=... :

 echo "TMSTMP: $tmstmp" "TMDELTA: $(( $(date -d "now" +%s) - $(date -d "$tmstmp" +%s) ))" "TMWINDOW: $(( 60*60*24*7 ))" 

пример

Для простоты я поставил это в скрипт и назвал его rprttime.bash :

 #!/bin/bash tail -n+2 file.csv | { while read line ; do tmstmp=$(echo "$line" | awk '{print $8}'); echo "TMSTMP: $tmstmp" "TMDELTA: $(( $(date -d "now" +%s) - $(date -d "$tmstmp" +%s) ))" "TMWINDOW: $(( 60*60*24*7 ))" [ $(( $(date -d "now" +%s) - $(date -d "$tmstmp" +%s) )) -lt $(( 60*60*24*7 )) ] && echo "$line"; done; } 

Теперь, когда мы запускаем его:

 $ ./rprttime.bash TMSTMP: 05/07/2013 TMDELTA: 5157421 TMWINDOW: 604800 TMSTMP: 08/05/2012 TMDELTA: 28917421 TMWINDOW: 604800 TMSTMP: 04/04/2013 TMDELTA: 8008621 TMWINDOW: 604800 TMSTMP: 04/03/2013 TMDELTA: 8095021 TMWINDOW: 604800 TMSTMP: 04/03/2013 TMDELTA: 8095021 TMWINDOW: 604800 TMSTMP: 3/22/2013 TMDELTA: 9131821 TMWINDOW: 604800 TMSTMP: 04/02/2013 TMDELTA: 8181421 TMWINDOW: 604800 TMSTMP: 11/15/2012 TMDELTA: 20101021 TMWINDOW: 604800 TMSTMP: 3/22/2013 TMDELTA: 9131821 TMWINDOW: 604800 

Если вы измените время от 7 дней до 60 дней и отключите линию отладки, вы увидите некоторые печатные строки:

 $ date Fri Jul 5 16:49:19 EDT 2013 $ ./rprttime.bash T001028 1 1 1 0 0 0 05/07/2013 

Еще один ответ с ограниченными вилками

Поскольку есть много вилок для выключения, есть способ bash для этого, используя sed и только 1 fork to /bin/date :

 sedstr="" { i=1; read now; while read line;do ((i++)); [ $(( (now-line) /86400 )) -gt 143 ] && sedstr="${i}d;$sedstr" done }< <( sed -ne $'s/^.*[ \t,]//g;y|-|/|;/[0-9]$/p;1inow' < file.tsv | date -f - +%s ) sed -e "$sedstr" < file.tsv Person ID VIP CS SS LT FTLT PS Modified Datestamp T001028 1 1 1 0 0 0 05-07-2013 T001261 1 1 1 0 0 1 04-04-2013 T001345 1 1 1 0 0 0 04-03-2013 T078503 1 1 1 0 0 0 04-03-2013 

Последняя команда sed может использоваться с -i для модификации inplace вместо вывода на консоль.

 echo $sedstr 10d;9d;8d;7d;3d; sed -e $sedstr -i file.tsv cat file.tsv Person ID VIP CS SS LT FTLT PS Modified Datestamp T001028 1 1 1 0 0 0 05-07-2013 T001261 1 1 1 0 0 1 04-04-2013 T001345 1 1 1 0 0 0 04-03-2013 T078503 1 1 1 0 0 0 04-03-2013 

Если вы подсчитаете дату, до которой строки будут проигнорированы до вызова awk, вы можете сделать это:

 awk -v cmpdate=20130628 '{line=$0; dateval=$8;FS="/"; $0=dateval; thisdate=$3*10000+$1*100+$2; if (thisdate>cmpdate) print line; FS=" ";}' file 

Изменить 1:

Сбросьте значение FS в исходное значение в конце. Я проверил свой код только с одной строкой ввода, так что это не помогло …

Поскольку, кажется, нет лучшего ответа, чем это (все целевое решение будет делать одну вилку в /bin/date для каждой строки), есть чистый и эффективный способ выполнить эту работу, но с использованием perl.

Вопрос для csv (значение, разделенное комой) и текущий tsv (tab sep vals), поэтому мой скрипт будет работать для любых значений вкладок , комы или пробела (просто найдите последнее поле).

Никакая вилка, perl не сделает сам синтаксический анализ даты:

 #!/usr/bin/perl -w use strict; use Date::Parse; my $day=7; if ($ARGV[0] && $ARGV[0] > 0) { $day=$ARGV[0]; shift; }; while (<>) { my @fields=split(/[ \t,]/); print if /^Person/ || str2time($fields[$#fields]) > time()-$day*86400; }; 

U может запускать это без аргумента, в качестве фильтра или с именем файла в качестве аргумента:

 ./dropOlderThan.pl < file.tsv Person ID VIP CS SS LT FTLT PS Modified Datestamp ./dropOlderThan.pl file.tsv Person ID VIP CS SS LT FTLT PS Modified Datestamp 

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

 ./dropOlderThan.pl 144 file.tsv Person ID VIP CS SS LT FTLT PS Modified Datestamp T001028 1 1 1 0 0 0 05-07-2013 T001261 1 1 1 0 0 1 04-04-2013 T001345 1 1 1 0 0 0 04-03-2013 T078503 1 1 1 0 0 0 04-03-2013 

И, наконец, если вы хотите изменить файл на месте:

 perl -i dropOlderThan.pl 144 file.tsv cat file.tsv Person ID VIP CS SS LT FTLT PS Modified Datestamp T001028 1 1 1 0 0 0 05-07-2013 T001261 1 1 1 0 0 1 04-04-2013 T001345 1 1 1 0 0 0 04-03-2013 T078503 1 1 1 0 0 0 04-03-2013 

Я бы сделал это с помощью Perl (запустите это с терминала):

 $ perl -lane 'BEGIN{$date=`date +%s`; chomp($date)} if($.==1){print} else{ $F[$#F]=~s/-/\//g; $fdate=`date -d "$F[$#F]" +%s`; chomp($fdate); print if $date-$fdate<604800; }' file.csv 

Этот скрипт работает, вычисляя сегодняшнюю дату за считанные секунды с эпохи , а затем перевод даты каждой строки в один и тот же формат, вычитая ее с сегодняшней даты и печати, только если она меньше 7 дней (7 * 24 * 60 * 60 = 604800).

ЗАМЕТКИ

  • Скрипт работает с секундами, это может быть слишком точным для того, что вы имели в виду. Дайте мне знать, если так, и я изменю его, чтобы работать на уровне дней.

  • Я также конвертирую MM-DD-YYYY в MM/DD/YYYY на лету, это может быть необязательно, если ваш входной файл однородно отформатирован, но он необходим для примера, который вы опубликовали.

  • Увеличение числового рисунка в файле
  • Как заменить определенную строку с помощью sed или awk на основе команды run
  • сопоставление шаблонов sed
  • Как найти и заменить только определенное слово (которое находится в конце файла) с помощью команды оболочки?
  • избегать разрыва строки
  • Создание отдельной таблицы из нескольких файлов
  • Замените пробелы в начале строки на "-"
  • Найдите (и разделите) общие начальные пробелы из файла / трубы
  • Объяснение для 'sed'
  • sed - шаблон только на некоторых предопределенных строках
  • Как заменить заголовок файла заголовком другого файла
  • Linux и Unix - лучшая ОС в мире.