为什么这个 Unzip shell 脚本在环境将 Dev 更改为 Prod 时表现不同?
Why this Unzip shell script behaves differently when environment change Dev to Prod?
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
输出:
Dev:
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
Prod:
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 开发集群 中时,它工作正常。但在生产集群中它不是。请找出上面脚本的行为。
for f in $files
中的分词好像有问题。通常 shell 应该像在 Dev 上那样在空格处拆分值 $files
。
在 for
循环的每个循环中,Dev f
被设置为来自 $files
的三个单词之一,Prod f
获得 $files
的完整值包括空格。
你在某处设置了变量 IFS
吗?
如果问题不在脚本的其他部分,您应该能够使用简化的脚本重现问题:
files="foo bar baz"
for f in $files
do
echo "available files are: $f"
done
如果这个最小脚本没有显示出差异,则问题出在脚本的其他部分。
要查看 IFS
的值在 Dev 和 Prod 上是否不同,您可以将其添加到最小脚本或 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
的位置。
顺便说一句:通常您可以在 grep 命令后省略 | tr '\n' ' '
。 shell 在处理 for f in $files
时应该接受 \n
作为分词字符。如果不是,这可能与您问题的根源有关。
编辑:逐行处理数据有更好的解决方案,参见
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
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
输出:
Dev:
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
Prod:
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 开发集群 中时,它工作正常。但在生产集群中它不是。请找出上面脚本的行为。
for f in $files
中的分词好像有问题。通常 shell 应该像在 Dev 上那样在空格处拆分值 $files
。
在 for
循环的每个循环中,Dev f
被设置为来自 $files
的三个单词之一,Prod f
获得 $files
的完整值包括空格。
你在某处设置了变量 IFS
吗?
如果问题不在脚本的其他部分,您应该能够使用简化的脚本重现问题:
files="foo bar baz"
for f in $files
do
echo "available files are: $f"
done
如果这个最小脚本没有显示出差异,则问题出在脚本的其他部分。
要查看 IFS
的值在 Dev 和 Prod 上是否不同,您可以将其添加到最小脚本或 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
的位置。
顺便说一句:通常您可以在 grep 命令后省略 | tr '\n' ' '
。 shell 在处理 for f in $files
时应该接受 \n
作为分词字符。如果不是,这可能与您问题的根源有关。
编辑:逐行处理数据有更好的解决方案,参见
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