首页 > 解决方案 > 为什么当环境将 Dev 更改为 Prod 时,此 Unzip shell 脚本的行为会有所不同?

问题描述

output_path=s3://output
unziped_dir=s3://2019-01-03
files=`hadoop fs -ls $output_path/ | awk '{print $NF}' | grep .gz$ | tr '\n' ' '`;
for f in $files
do   
echo "available files are: $f"
filename=$(hadoop fs -ls $f | awk -F '/' '{print $NF}' | head -1)
hdfs dfs -cat $f | gzip -d | hdfs dfs -put - $unziped_dir"/"${filename%.*}
echo "unziped file names: ${filename%.*}"
done

输出:

开发:

available files are: s3://2019-01-03/File_2019-01-03.CSV.gz
unziped file names: File_2019-01-03.CSV
available files are: s3://2019-01-03/Data_2019-01-03.CSV.gz
unziped file names: Data_2019-01-03.CSV
available files are: s3://2019-01-03/Output_2019-01-03.CSV.gz
unziped file names: Output_2019-01-03.CSV

产品:

available files are: s3://2019-01-03/File_2019-01-03.CSV.gz s3://2019-01-03/Data_2019-01-03.CSV.gz s3://2019-01-03/Output_2019-01-03.CSV.gz 
unziped file names: 

我正在尝试查看目录并识别 .gz 文件并迭代它们以解压缩所有 .gz 文件并存储到不同的目录中。但是当我在EMR 开发集群中运行这个脚本时,它工作正常。但在产品集群中它不是。请找到上面脚本的行为。

标签: shellapache-sparkunixhadoop2

解决方案


单词拆分似乎有问题for f in $files。通常,shell 应该$files像在 Dev 上那样在空格处拆分值。On Devf设置为$files循环的每个循环中的三个单词之一for,on Prodf获得$files包含空格的完整值。

你在IFS某处设置变量吗?

如果问题不在脚本的其他部分,您应该能够使用简化的脚本重现问题:

files="foo bar baz"
for f in $files
do   
  echo "available files are: $f"
done

如果这个最小脚本没有显示出差异,则问题出在脚本的其他部分。

要查看 Dev 和 Prod 的值是否不同,您可以将其添加到最小脚本或循环IFS之前的原始脚本:for

# To see if IFS is different. With the default value (space, tab, newline) the output should be
# 0000000   I   F   S   =   #      \t  \n   #  \n
# 0000012
echo "IFS=#${IFS}#" | od -c

如果您看到值的差异,则IFS必须找出IFS修改的位置。

顺便说一句:通常你可以| tr '\n' ' '在 grep 命令之后省略。处理时,shell 应接受\n作为分词字符for f in $files。如果不是,这可能与您的问题的根源有关。

编辑:有一个更好的解决方案来逐行处理数据,请参阅
https://mywiki.wooledge.org/DontReadLinesWithFor
https://mywiki.wooledge.org/BashFAQ/001

您应该使用while read... 而不是for...

修改后的脚本(未经测试)

output_path=s3://output
unziped_dir=s3://2019-01-03

hadoop fs -ls "$output_path"/ | awk '{print $NF}' | grep .gz$ | while IFS= read -r f
do   
    echo "available files are: $f"
    filename=$(hadoop fs -ls "$f" | awk -F '/' '{print $NF}' | head -1)
    hdfs dfs -cat "$f" | gzip -d | hdfs dfs -put - "${unziped_dir}/${filename%.*}"
    echo "unziped file names: ${filename%.*}"
done

推荐阅读