如何在bash中将`ls -l`的输出解析为多个变量?

时间:2019-07-10 12:11:16

标签: bash ftp ncftp

已经有关于此主题的一些答案,但是几乎所有人都说解析ls -l的输出很不好,因此建议使用其他方法。

但是,我正在使用ncftpls -l,所以我不能使用shell glob或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在awk字符串中的$ 9和$ 5之间交替。

如果每次迭代我都能够获取文件名并将其文件化为单独的变量,则可以简单地使用stat -c "%s" $i来获取本地大小并将其与远程大小进行比较。然后在我还没有的每个远程文件上添加一个简单的ncftpget。我也修改了lftp之类的同步程序,但是运气不太好,宁愿这样。

感谢您的帮助!

1 个答案:

答案 0 :(得分: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