Каждый день каждые 6 часов мне приходится скачивать bz2
файлов с веб-сервера, распаковывать их и объединять в один файл. Это должно быть максимально эффективным и быстрым, поскольку мне нужно дождаться завершения фазы загрузки и распаковки, прежде чем продолжить слияние.
Я написал несколько функций bash, которые принимают в качестве входных данных некоторые строки для создания URL-адреса загружаемых файлов в качестве соответствующего шаблона. Таким образом, я могу передать соответствующий шаблон непосредственно wget
без необходимости создавать локально список содержимого сервера, который затем будет передан в виде списка с -i
до wget
. Моя функция выглядит примерно так
parallelized_extraction(){
i=0
until [ `ls -1 ${1}.bz2 2>/dev/null | wc -l ` -gt 0 -o $i -ge 30 ]; do
((i++))
sleep 1
done
while [ `ls -1 ${1}.bz2 2>/dev/null | wc -l ` -gt 0 ]; do
ls ${1}.bz2| parallel -j+0 bzip2 -d '{}'
sleep 1
done
}
download_merge_2d_variable()
{
filename="file_${year}${month}${day}${run}_*_${1}.grib2"
wget -b -r -nH -np -nv -nd -A "${filename}.bz2" "url/${run}/${1,,}/"
parallelized_extraction ${filename}
# do the merging
rm ${filename}
}
который я называю download_merge_2d_variable name_of_variable
. Я смог ускорить код, написав функцию parallelized_extraction
, которая занимается распаковкой загруженных файлов, пока wget
работает в фоновом режиме. Для этого я сначала жду появления первого файла .bz2
, затем запускаю распараллеленное извлечение до тех пор, пока на сервере не появится последний файл .bz2
(это то, что делают два цикла until
и while
).
Я очень доволен этим подходом, однако я думаю, что его можно улучшить. Вот мои вопросы:
- как я могу запустить несколько экземпляров
wget
для выполнения параллельных загрузок, если мой список файлов указан как соответствующий шаблон? Должен ли я писать несколько шаблонов сопоставления с фрагментами данных внутри или мне обязательно нужно загружать список содержимого с сервера, разделять этот список и затем передавать его в качестве входных данных дляwget
? parallelized_extraction
может дать сбой, если загрузка файлов идет очень медленно, так как он не найдет новый файлbz2
для извлечения и выйдет из цикла на следующей итерации, хотяwget
все еще работает в фоновом режиме. Хотя это никогда не случалось со мной, это возможность. Чтобы позаботиться об этом, я попытался добавить условие ко второму, запустивPID
изwget
в фоновом режиме, чтобы проверить, существует ли он, но почему-то он не работает.
parallelized_extraction(){
# ...................
# same as before ....
# ...................
while [ `ls -1 ${1}.bz2 2>/dev/null | wc -l ` -gt 0 -a kill -0 ${2} >/dev/null 2>&1 ]; do
ls ${1}.bz2| parallel -j+0 bzip2 -d '{}'
sleep 1
done
}
download_merge_2d_variable()
{
filename="ifile_${year}${month}${day}${run}_*_${1}.grib2"
wget -r -nH -np -nv -nd -A "${filename}.bz2" "url/${run}/${1,,}/" &
# get ID of process running in background
PROC_ID=$!
parallelized_extraction ${filename} ${PROC_ID}
# do the merging
rm ${filename}
}
Любая подсказка, почему это не работает? Любые предложения о том, как улучшить мой код? Спасибо
ОБНОВЛЕНИЕ Я публикую здесь свое рабочее решение, основанное на принятом ответе, если кому-то интересно.
# Extract a plain list of URLs by using --spider option and filtering
# only URLs from the output
listurls() {
filename="$1"
url="$2"
wget --spider -r -nH -np -nv -nd --reject "index.html" --cut-dirs=3 \
-A $filename.bz2 $url 2>&1\
| grep -Eo '(http|https)://(.*).bz2'
}
# Extract each file by redirecting the stdout of wget to bzip2
# note that I get the filename from the URL directly with
# basename and by removing the bz2 extension at the end
get_and_extract_one() {
url="$1"
file=`basename $url | sed 's/\.bz2//g'`
wget -q -O - "$url" | bzip2 -dc > "$file"
}
export -f get_and_extract_one
# Here the main calling function
download_merge_2d_variable()
{
filename="filename.grib2"
url="url/where/the/file/is/"
listurls $filename $url | parallel get_and_extract_one {}
# merging and processing
}
export -f download_merge_2d_variable_icon_globe