过去24小时将文件从HDFS的多个目录复制到本地

时间:2019-03-26 18:46:09

标签: bash hadoop hdfs

从HDFS到本地获取数据时遇到问题。 例如:

/path/to/folder/report1/report1_2019_03_24-03_10*.csv
/path/to/folder/report1/report1_2019_03_24-04_12*.csv
...
/path/to/folder/report1/report1_2019_03_25-05_12*.csv
/path/to/folder/report1/report1_2019_03_25-06_12*.csv
/path/to/folder/report1/report1_2019_03_25-07_11*.csv
/path/to/folder/report1/report1_2019_03_25-08_13*.csv
/path/to/folder/report2/report2_out_2019_03_25-05_12*.csv
/path/to/folder/report2/report2_out_2019_03_25-06_11*.csv
/path/to/folder/report3/report3_TH_2019_03_25-05_12*.csv

因此,我需要输入每个文件夹(report1,report2,report3 ...,但并非所有文件夹都以“ report”开头),然后输入从前24小时复制到本地的CSV文件,并且每个早上4点(我可以通过crontab安排时间)。 问题是我不知道如何遍历文件并将时间戳记作为参数传递。

我已经尝试过类似的方法(在Stack Overflow上找到)

/datalake/hadoop/bin/hadoop fs -ls /path/to/folder/report1/report1/*    |   tr -s " "    |    cut -d' ' -f6-8    |     grep "^[0-9]"    |    awk 'BEGIN{ MIN=1440; LAST=60*MIN; "date +%s" | getline NOW } { cmd="date -d'\''"$1" "$2"'\'' +%s"; cmd | getline WHEN; DIFF=NOW-WHEN; if(NOW > DIFF){ print "Migrating: "$3; system("datalake/hadoop/bin/hadoop fs -copyToLocal /path/to/local_dir/"$3) }}'

但是这是复制早于几天的文件,并且仅从一个目录(在本例中为report1)复制文件。

有什么方法可以使此操作更加灵活和正确。如果可以使用bash而不是Python来解决问题,那就太好了。 任何建议都值得欢迎,或者可以链接到存在类似问题的良好答案。

此外,也不必处于某个循环中。我可以为每个报告使用分隔的代码行。

2 个答案:

答案 0 :(得分:3)

注意:,我无法对此进行测试,但是您可以通过查看输出来逐步测试这一点:

通常我会说Never parse the output of ls,但是使用hadoop时您实际上没有选择,因为没有等效于find的选择。 (从2.7.0版开始可以找到,但是根据documentation来说,它是非常有限的)

步骤1:递归ls

$ hadoop fs -ls -R /path/to/folder/

步骤2:使用awk仅选择文件,仅选择csv文件
目录通过以d开头的权限来识别,因此我们必须排除这些权限。并且csv文件由csv结尾的最后一个字段识别:

$ hadoop fs -ls -R /path/to/folder/ | awk '!/^d/ && /\.csv$/'

确保您在此处不会出现有趣的行,这些行是空的或只是目录名...

第3步::继续使用awk处理时间。我假设您有任何标准的awk,所以我不会使用GNU扩展。 hadoop将输出时间格式为yyyy-MM-dd HH:mm。这是一种可排序的格式,位于字段6和7中:

$ hadoop fs -ls -R /path/to/folder/  \
   | awk -v cutoff="$(date -d '-24 hours' '+%F %H:%M')" \
         '(!/^d/) && /\.csv$/ && (($6" "$7) > cutoff)'

第4步:一份一份复制文件:

首先,检查要执行的命令:

$ hadoop fs -ls -R /path/to/folder/  \
   | awk -v cutoff="$(date -d '-24 hours' '+%F %H:%M')" \
         '(!/^d/) && /\.csv$/ && (($6" "$7) > cutoff) {
            print "migrating", $NF
            cmd="hadoop fs -get "$NF" /path/to/local/"
            print cmd
            # system(cmd)
         }'

(如果要执行,则删除#

$ hadoop fs -ls -R /path/to/folder/  \
   | awk -v cutoff="$(date -d '-24 hours' '+%F %H:%M')" \
         '(!/^d/) && /\.csv$/ && (($6" "$7) > cutoff) {
            print $NF
         }' | xargs -I{} echo hadoop fs -get '{}' /path/to/local/

(如果要执行,请删除回声)

答案 1 :(得分:1)

通过将“ find”与“ cp”结合使用,可以使其更简单,例如:

find /path/to/directory/ -type f -name "*.csv" | xargs cp -t /path/to/copy

如果要清除24小时以上的文件目录,可以使用:

find /path/to/files/ -type f -name "*.csv" -mtime +1 | xargs rm -f

也许您可以将它们实现为脚本,然后将其设置为Cron上的任务。