удалить строки, которые новее указанной даты в файле

8

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

buildsave.txt

647919 2013/11/30
647946 2013/11/30
647955 2013/12/01
648266 2013/12/03
648267 2013/12/03
648674 2013/12/04

Я хотел бы удалить строки, которые новее, чем 2013/12/03, оставив только

647919 2013/11/30
647946 2013/11/30
647955 2013/12/01

Как это можно сделать через bash?

Джейсон Дж
источник

Ответы:

4

Если ваша система включает версию команды GNU date, вы можете использовать ее для преобразования поля даты (после удаления завершающего <br>, если оно есть) в секунды с момента начала и сравнения непосредственно с датой отсечения в том же формате, например в bash

testsecs=$(date +%s --date="2013/12/03")
while IFS= read -r line; do
  read -r x d <<< "$line" 
  if (( $(date +%s --date="${d%<br>}") < $testsecs )); then
    printf '%s\n' "$line"
  fi
done < buildsave.txt

[Обратите внимание, что это не выполняет удаление на месте - вам нужно сохранить результаты во временный файл и переименовать.]

steeldriver
источник
Вы, сэр, спасли меня от головной боли. Это именно то, что я искал!
Джейсон Дж
Тьфу! Эти даты сортируются одинаково лексикографически и хронологически, нет необходимости преобразовывать их в целочисленные и выполнять 5 команд, создавать один временный файл и два канала на строку!
Стефан Шазелас
9

Эти даты сортируются по лексикографически и хронологически одинаково, так что это всего лишь вопрос лексического сравнения:

awk '$2 < "2013/12/03"'
Стефан Шазелас
источник
2

Я предполагаю, что <br>в вашем вопросе в конце dateстолбца есть что-то нежелательное. В любом случае, он может быть легко удален, если он присутствует. Однако, перейдя к основной части, вы можете достичь того, что вы пытаетесь сделать, используя

sort -k 2n filename.txt

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

sort -k 2n filename.txt | awk '/2013\/12\/03/ {exit} {print}' 

объяснение

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

тестирование

cat filename.txt

647919 2014/01/01
647946 2012/11/30
647955 2011/01/04
648266 2013/12/03
648267 2013/12/03
648674 2013/12/04

Теперь sort -k 2n filename.txtвывод

647955 2011/01/04
647946 2012/11/30
648266 2013/12/03
648267 2013/12/03
648674 2013/12/04
647919 2014/01/01

Теперь мы удовлетворены тем, что файл отсортирован по второму столбцу. Теперь, чтобы выбрать значения UPTO определенной даты,

sort -k 2n filename.txt | awk '/2013\/12\/03/ {exit} {print}' 

В приведенном выше примере я получаю все значения до 2013/12/03. Выход есть,

647955 2011/01/04
647946 2012/11/30

Нет, <br>это часть моего файла

Если это так, мы можем немного изменить команду, как показано ниже.

awk '{print $1, substr($2, 1, length($2)-4)}' filename.txt | 
sort -k 2n filename.txt | awk '/2013\/12\/03/ {exit} {print}' 

Поэтому я просто удаляю все <br>теги из второго столбца, а затем добавляю вышеупомянутую команду.

Ссылки

https://unix.stackexchange.com/a/11323/47538

https://unix.stackexchange.com/a/83069/47538

Рамеш
источник
спасибо за ваш вклад. это действительно работает очень хорошо, однако, условие для выхода не всегда работает, когда конкретная дата не существует в файле.
Джейсон Дж
нет, кажется, что добавлены теги br просто для удобства чтения. Их нельзя увидеть в первой ревизии
Брайам
-1

Быстрое и грязное решение для одной даты, которую вы дали, просто удалите все строки с помощью sed, которые соответствуют датам позже этой даты:

sed -i "" "#[0-9]* 2013/12/0[4-9]#d" testfile.txt
sed -i "" "#[0-9]* 2013/12/[123][0-9]#d" testfile.txt
sed -i "" "#[0-9]* 2014/[0-9][0-9]/[0-3][0-9]#d" testfile.txt

-I "" заменяет непосредственно внутри файла и не создает резервную копию, но вы также можете передать тестовый файл через все 3 команды sed без -i "".

В зависимости от вашей системы (Linux или Mac) вы можете пропустить "" после -i, а иногда вам потребуется параметр -e для регулярных выражений. Должен попробовать то, что работает для вас.

Связанный вопрос с дополнительной информацией о sed: /programming/5410757/

Toppy
источник
#это комментарий команда в sed, так что те не будут ничего делать. Используйте, sed '\#patter#d'если вы хотите другой разделитель RE, чем /. [0-9]*Часть избыточна без ^якоря. нужен-e только тогда, когда вы хотите передать несколько выражений. linux - это ядро, mac - это компьютерный бренд, и ни один из них не имеет к этому никакого отношения . Различия между GNU и FreeBSD (которые OS / X (как встречается на некоторых маках) унаследованы). sedsedsed
Стефан Шазелас