Как разобрать вывод `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