Рассчитать записи разницы даты / во времени. В двух файлах в Bash Script

Потому что это режим vi , а не режим vim . daw , diw предназначены только для vim и не являются самыми полезными. Вы можете сделать то же самое с bdw , bde - Stephane Chazelas

При этом вы можете использовать bindkey -s для привязки одной строки к другой:

bindkey -a -s "diw" "bde"
bindkey -a -s "daw" "bdw"

Теперь при вводе diw bde отправляется обратно.

-a необходим для добавления привязки к режиму vicmd .

Обновление для zsh версии ≥ 5.0.8

Начиная с версии 5.0.8 zsh также поддерживает текстовые объекты в стиле vim. Так что daw и diw должны работать из коробки.

0
19.12.2018, 17:12
4 ответа

как однострочник

while read -r StartDate  && read -r FinalDate <&3; do if [[ ${StartDate} != "INVALID" && ${FinalDate} != "INVALID" ]]; then diff=$(expr $(date -d "${FinalDate}" +"%s") - $(date -d "${StartDate}" +"%s")); printf '%dd:%dh:%dm:%ds\n' $((${diff}/86400)) $((${diff}%86400/3600)) $((${diff}%3600/60)) $((${diff}%60));else echo INVALID; fi; done < startedfile 3<finishedfile

как сценарий

#!/bin/bash

while read -r StartDate  && read -r FinalDate <&3; do 
    if [[ ${StartDate} != "INVALID" && ${FinalDate} != "INVALID" ]]; then 
        diff=$(expr $(date -d "${FinalDate}" +"%s") - $(date -d "${StartDate}" +"%s")); 
        printf '%dd:%dh:%dm:%ds\n' $((${diff}/86400)) $((${diff}%86400/3600)) $((${diff}%3600/60)) $((${diff}%60));
    else 
        echo INVALID; 
    fi; 
done < startedfile 3<finishedfile

Это даст такой результат:

0d:0h:2m:13s
0d:1h:0m:55s
INVALID
0d:7h:1m:36s
INVALID
INVALID

Затем вы можете просто вывести это в нужный файл.


РЕДАКТИРОВАТЬ

Как было предложено в комментариях, это можно упростить, установив пакет dateutilsи используя команду datediff.

while read -r StartDate  && read -r FinalDate <&3; do if [[ ${StartDate} != "INVALID" && ${FinalDate} != "INVALID" ]]; then datediff "${StartDate}" "${FinalDate}" -f "%dd:%Hh:%Mm:%Ss";else echo INVALID; fi; done < started.txt 3<finished.txt 

В сценарии

#!/bin/bash

while read -r StartDate  && read -r FinalDate <&3; do 
    if [[ ${StartDate} != "INVALID" && ${FinalDate} != "INVALID" ]]; then 
        datediff "${StartDate}" "${FinalDate}" -f "%dd:%Hh:%Mm:%Ss";
    else 
        echo INVALID; 
    fi; 
done < startedfile 3<finishedfile
3
28.01.2020, 02:23

Думаю, мне удалось решить вашу проблему с помощью следующего сценария bash:

#!/usr/bin/env bash

sfile=/path/to/start
efile=/path/to/end
ofile=/path/to/out
n=0

while read -r line; do
    ((n++))
    if [[ $line == 'INVALID' ]]; then
        echo "INVALID"
        continue
    fi
    start=$(date -u -d "$line" "+%s")
    end=$(date -u -d "$(sed -n "${n}p" "$efile")" "+%s")
    date -u -d "0 $end sec - $start sec" +"%H:%M:%S"
done<"$sfile" >"$ofile"

Каждая строка начального файла будет прочитана и сравнена с соответствующей строкой в ​​конечном файле. Если строка содержит «INVALID», она выдаст «INVALID» и перейдет к следующей итерации цикла.

0
28.01.2020, 02:23

Использование ddiffиз GNU dateutilsиbash:

#!/bin/bash

paste STARTED COMPLETED |
while IFS=$'\t' read start compl; do
    if [ "$start" = "INVALID" ] || [ "$compl" = "INVALID" ]; then
        echo 'INVALID'
    else
        ddiff -f '%0H:%0M:%0S' "$start" "$compl"
    fi
done

Предполагая, что входные файлы называются STARTEDи COMPLETED, это создает ввод с разделителями табуляции -для цикла whileс временем начала в первом поле и временем завершения во втором поле. Он читает их и проверяет, соответствует ли какое-либо из двух значений времени INVALID. Если нет, он вызывает ddiffвместе с ними.

Вывод этого может быть сохранен в файл с перенаправлением после doneв конце или после имени скрипта в командной строке при вызове скрипта.

Запуск на предоставленных данных:

$ bash script.sh
00:02:13
01:00:55
07:01:36
INVALID
INVALID
0
28.01.2020, 02:23

Сzsh:

#! /bin/zsh -
# usage: that-script file1 file2
zmodload zsh/datetime
while
  IFS= read -ru3 a &&
   IFS= read -ru4 b
do
  if
    strftime -rs at '%Y-%m-%d %H:%M:%S' "$a" 2> /dev/null &&
      strftime -rs bt '%Y-%m-%d %H:%M:%S' "$b" 2> /dev/null
  then
    d=$((bt - at))
    printf '%02d:%02d:%02d\n' $((d/3600)) $(((d/60)%60)) $((d%60))
  else
     printf '%s\n' $a
  fi
done 3< ${1?} 4< ${2?}

Это по-прежнему использует цикл оболочки для обработки текста , что обычно считается плохой практикой но, по крайней мере, здесь мы используем только встроенные команды, что означает, что производительность не будет такой ужасной, как если бы вы вызывали две внешние команды GNU dateдля каждой строки ввода.

0
28.01.2020, 02:23

Теги

Похожие вопросы