Как разобрать вывод `ls -l` в несколько переменных в bash?

На эту тему уже есть несколько ответов, но почти все они говорят, что разбирать выходные данные плохо ls -lи, следовательно, предложить другие методы.

Тем не менее, я использую ncftpls -lи поэтому я не могу использовать такие вещи, как ракушки или find - Я думаю, у меня есть реальная необходимость на самом деле разобрать ls -l выход. Не волнуйтесь, если вы не знакомы с ncftpls, вывод возвращается в том же формате, как если бы вы просто использовали ls -l,

В общедоступном удаленном каталоге ftp есть список файлов, и я не хочу обременять удаленный сервер повторной загрузкой каждого из нужных файлов каждый раз, когда запускается мой cronjob. Я хочу проверить для каждого из подмножества файлов в каталоге ftp, существует ли файл локально; если нет, загрузите его.

Это достаточно просто, я просто использую

tdy=`date -u '+%Y%m%d'`_

# Today's files
for i in $(ncftpls 'ftp://theftpserver/path/to/files' | grep ${tdy}); do
    if [ ! -f $i ]; then
        ncftpget "ftp://theftpserver/path/to/files/${i}"
    fi
done

Но я столкнулся с проблемой, что иногда задание cron загружает файл, который не завершил загрузку, и поэтому при следующем запуске он пропускает частично загруженный файл.

Поэтому я хотел добавить проверку, чтобы убедиться, что для каждого файла, который у меня уже есть, размер локального файла соответствует размеру того же файла на удаленном сервере.

Я думал о том, чтобы разобрать вывод ncftpls -l и используя awk, что-то вроде

for i in $(ncftpls -l 'ftp://theftpserver/path/to/files' | awk '{print $9, $5}'); do
    ...
    x=filesize   # somehow get the file size and the filename
    y=filename   # from $i on each iteration and store in variables
    ...
done

но я не могу получить и имя файла, и размер файла с сервера в локальные переменные на одной и той же итерации цикла; $i чередуется между $9 и $5 в строке awk при каждой итерации.

Если бы мне удавалось получить имя файла и размер файла в отдельные переменные с каждой итерацией, я мог бы просто использовать stat -c "%s" $i чтобы получить локальный размер и сравнить его с удаленным размером. Тогда это просто ncftpget на каждом удаленном файле, которого у меня еще нет. Я возился с синхронизирующими программами вроде lftp тоже, но не очень повезло, и я бы предпочел сделать это таким образом.

Любая помощь приветствуется!

1 ответ

Решение

Цикл for разделяется, когда он видит любые пробелы, такие как пробел, табуляция или перевод строки. Итак, IFS нужен перед циклом, (есть много вопросов о...)

IFS=$'\n' && for i in $(ncftpls -l 'ftp://theftpserver/path/to/files' | awk '{print $9, $5}'); do

echo $i | awk '{print $NF}' # filesize 
echo $i | awk '{NF--; print}' # filename
# you may have spaces in filenames, so is better to use last column for awk

done

Я думаю, что лучший способ использовать, а не для, так

ls -l | while read i
do
echo $i | awk '{print $9, $5}'

#split them if you want 
x=echo $i | awk '{print $5}'
y=echo $i | awk '{print $9}'

done
Другие вопросы по тегам