Почему этот сценарий оболочки Unzip ведет себя по-разному, когда среда меняет Dev на Prod? - PullRequest
0 голосов
/ 09 января 2019
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 dev cluster , он работает нормально. Но в кластере продуктов его нет. Пожалуйста, найдите поведение скрипта выше.

1 Ответ

0 голосов
/ 10 января 2019

Кажется, есть проблема с разделением слов в for f in $files. Обычно оболочка должна разделять значение $files на пробелы, как это происходит на Dev. На Dev f устанавливается одно из трех слов от $files в каждом цикле цикла for, на 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 изменяется.

Кстати: обычно вы можете опустить | tr '\n' ' ' после команды grep. Оболочка должна принимать \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
...