1
votes

Recherche entre deux dates en utilisant sed sur s3

J'essaye d'obtenir tous les fichiers entre deux dates sur s3 -

echo "2018-01-01" |  sed -n "/2018-06-01/,/`date +%Y-%m-%d -d '30 days ago'`/p"
echo "2019-01-01" |  sed -n "/2018-06-01/,/`date +%Y-%m-%d -d '30 days ago'`/p"
echo "2019-02-01" |  sed -n "/2018-06-01/,/`date +%Y-%m-%d -d '30 days ago'`/p"
echo "2019-02-01" |  sed -n  "/2018-06-01/,/2019-01-05/p"
echo "2019-06-30" |  sed -n  "/2018-06-01/,/2019-01-05/p"

Cela a tendance à me donner toutes les données. Utilisé mais cela ne fonctionne pas - https://stackoverflow.com/a/29412898/2251058 (ne filtrer quoi que ce soit) Est-ce une bonne façon de le faire?

Toute aide est appréciée.

Mises à jour

Comme demandé - RavinderSingh13

J'ai utilisé -n as et trouvé sans -n la commande sed agit comme une commande cat.

Comme suggéré par jhnc, j'ai ajouté -n pour l'utiliser comme commande grep et cela me donne un résultat vide

Un exemple de modèle d'entrée est quelque chose comme suit avec un résultat vide

2018-06-01 13:32:20      <filesize> <filepath>....gz
.
.
.
.
2019-02-04 00:13:12      12344 <filepath>....gz

Avec -n ajouté (à utiliser comme grep), j'ai eu un bogue ci-dessus où -n n'a pas été utilisé, il n'affiche aucune sortie. Pour vérifier, j'ai utilisé les commandes ci-dessous. Il ne donne aucune sortie.

aws s3 ls 's3://big-data-analytics-prod/LZ/copycat/emailstats/' --recursive |  sed  "/2018-06-01/,/`date +%Y-%m-%d -d '30 days ago'`/p"


5 commentaires

Veuillez mentionner la sortie de la commande aws s3 ls 's3: // big-data-analytics-prod / LZ / copycat / emailstats /' --recursive et mentionnez également la sortie de l'échantillon attendu car ce n'est pas le cas clair.


@ RavinderSingh13 Ajout d'un exemple de sortie. Faites-moi savoir si quelque chose d'autre est nécessaire. Fondamentalement, j'utilise la date de aws s3 ls (liste des fichiers) à grep


Vous pouvez remplacer sed par sort | sed -n . Et je suppose que vous savez que vous n'obtiendrez que le premier fichier de la date de fin. Et pour être complet, commencez chaque // par ^


@jhnc La commande ls est triée dans ce cas. J'ai essayé avec sed -n cela donne des résultats vides à la fois valides et invalides echo "2018-08-30" | sed -n "/ 2018-06-01 /, /` date +% Y-% m-% d -d 'il y a 30 jours'` / p " echo" 2018-06-30 " | sed -n "/ 2018-06-01 /, /` date +% Y-% m-% d -d 'il y a 30 jours'` / p "


Je viens de réaliser: cela ne fonctionnera pas si la date de début n'apparaît pas dans la liste


3 Réponses :


2
votes

Le code sed donné dans la question ne fonctionnera correctement que si la date de début apparaît dans la liste.

Nous devons faire des comparaisons de chaînes plutôt que des expressions rationnelles. Soit awk, soit perl est à la hauteur de la tâche.

Perl fantaisie:

awk '$0>="2018-06-01" && $0<="2019-01-01" {print}'

Simple awk (pourrait intégrer la date d'appel de la même manière que sed d'origine) :

#!/usr/bin/perl

# Usage: $0 date1 date2
# where dates can be anything supported by date(1)
# remember to "quote whitespace"

# fancy date parsing
open(my $cmd, '-|', 'date', '+%Y-%m-%d %H:%M:%S', '--date', $ARGV[0]||'1970-01-01') or die $!;
my $start = <$cmd>;
chomp $start;
close $cmd;
open(my $cmd, '-|', 'date', '+%Y-%m-%d %H:%M:%S', '--date', $ARGV[1]||'now') or die $!;
my $end = <$cmd>;
chomp $end;
close $cmd;

# start should be earlier than end
($start, $end) = ($end, $start) if $start gt $end;

while (<STDIN>) {
    print if $_ ge $start && $_ le $end;
}


2 commentaires

Oui, j'ai fait la même chose plus tôt, j'ai oublié de le mettre comme réponse - aws s3 ls 's3: // big-data-analytics-prod / LZ / copycat / emailstats /' --recursive | awk -v begintime = '2018-06-01' -v endtime = "` date +% Y-% m-% d -d 'il y a 30 jours'` "-v bucket =" s3: // big-data- analytics-prod / "'{if ($ 1> = beginintime && $ 1 <= endtime) {print bucket $ 4}}'


awk est préférable d'utiliser pour cela.



1
votes

Pendant ce temps, j'ai appris un peu de awk et à la place, j'ai utilisé awk pour calculer cela, mais j'ai oublié de partager comme réponse.

aws s3 ls 's3://big-data-analytics-prod/LZ/copycat/emailstats/' --recursive  |  awk -v begintime="2018-06-01" -v endtime="`date +%Y-%m-%d -d '30 days ago'`"  '{if($1>=begintime && $1<=endtime) {print $4}}'

OU dans une ligne

endtime=`date +%Y-%m-%d -d '-30 day'`
begintime="2018-06-01"
bucket="s3://big-data-analytics-prod/"
path='s3://big-data-analytics-prod/LZ/copycat/emailstats/'
aws s3 ls path --recursive  |  awk '{if($1>=$begintime && $1<=$endtime) {print $4} }'


0 commentaires

2
votes

En guise de solution simple (sans sed), essayez ce qui suit:

#!/bin/bash

# usage: thiscommand startdate enddate
#    starddate and enddate should be in the format: yyyy-mm-dd

start=${1//-/}
end=${2//-/}

while read -r date rest; do
    date2=${date//-/}
    if ((start <= date2 && date2 <= end)); then
        echo "$date $rest"
    fi
done < <(aws s3 ls 's3://big-data-analytics-prod/LZ/copycat/emailstats/' --recursive)

où le fichier d'exemple input.txt ressemble à: p >

2019-01-01 01:23:45      <filesize> <filepath>....gz
2019-01-30 00:22:45      <filesize> <filepath>....gz
2019-02-01 11:03:05      <filesize> <filepath>....gz
2019-02-02 02:24:55      <filesize> <filepath>....gz

Appelez ensuite le script avec:

$ ./thisscript 2019-01-01 2019-02-02

renvoie:

2018-06-01 13:32:20      <filesize> <filepath>....gz
2019-01-01 01:23:45      <filesize> <filepath>....gz
2019-01-30 00:22:45      <filesize> <filepath>....gz
2019-02-01 11:03:05      <filesize> <filepath>....gz
2019-02-02 02:24:55      <filesize> <filepath>....gz
2019-02-04 00:13:12      12344 <filepath>....gz

Si vous souhaitez traiter directement la sortie de la commande aws , vous pouvez dire:

#!/bin/bash

# usage: thiscommand startdate enddate
#    starddate and enddate should be in the format: yyyy-mm-dd

start=${1//-/}
end=${2//-/}

while read -r date rest; do
    date2=${date//-/}
    if ((start <= date2 && date2 <= end)); then
        echo "$date $rest"
    fi
done < input.txt

Vous verrez qu'il n'y a pas d'astuce: c'est juste convertit le format de la date en nombres simples et les compare arithmétiquement.


2 commentaires

Agréable. Si nous utilisons bash, les s /// ne sont pas nécessaires comme nous pouvons le faire ["$ start" \ <"$ date2"] && ["$ date2" \ < "$ end"] directement (bien que cela changera la plage sélectionnée sauf si nous testons également = qui annule l'enregistrement de caractères!)


Absolument. Merci de me rappeler que nous pouvons effectuer une comparaison de l'ordre du dictionnaire sans déhyphation. J'ai peut-être été pris dans le concept de conversion en valeurs numériques.