我有从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,那将会很棒。欢迎任何建议或链接到类似问题的良好答案。
而且,没有必要在某个循环中。我可以为每个报告使用分隔的代码行。
注意:我无法对此进行测试,但您可以通过查看输出逐步测试:
通常我会说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/
(如果要执行,请删除echo)
您可以通过将“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上的任务。