Как разобрать вывод `ls -l` в несколько переменных в bash? - PullRequest
0 голосов
/ 10 июля 2019

На эту тему уже есть несколько ответов, но почти все они говорят, что плохо разбирать вывод 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 Ответ

1 голос
/ 10 июля 2019

для цикла разделяется, когда он видит любые пробелы, такие как пробел, табуляция или перевод строки.Итак, 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
...