如何将 ls -l 的输出解析为 bash 中的多个变量?
How to parse the output of `ls -l` into multiple variables in bash?
已经有一些关于这个主题的答案,但几乎所有的答案都说解析 ls -l
的输出是不好的,因此建议使用其他方法。
但是,我正在使用 ncftpls -l
,所以我不能使用像 shell glob 或 find
这样的东西——我认为我真的需要实际解析ls -l
输出。如果您不熟悉 ncftpls
,请不要担心,输出 returns 的格式与您刚刚使用 ls -l
.
的格式完全相同
在 public 远程 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 , }'); 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
这样的同步程序,但运气不佳,宁愿这样做。
感谢任何帮助!
for 循环在看到任何白色space 时分裂,例如 space、制表符或换行符。所以,在循环之前需要IFS,(关于...的问题很多)
IFS=$'\n' && for i in $(ncftpls -l 'ftp://theftpserver/path/to/files' | awk '{print , }'); 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
我认为更好的方法是使用 while not for,所以
ls -l | while read i
do
echo $i | awk '{print , }'
#split them if you want
x=echo $i | awk '{print }'
y=echo $i | awk '{print }'
done
已经有一些关于这个主题的答案,但几乎所有的答案都说解析 ls -l
的输出是不好的,因此建议使用其他方法。
但是,我正在使用 ncftpls -l
,所以我不能使用像 shell glob 或 find
这样的东西——我认为我真的需要实际解析ls -l
输出。如果您不熟悉 ncftpls
,请不要担心,输出 returns 的格式与您刚刚使用 ls -l
.
在 public 远程 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 , }'); 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
这样的同步程序,但运气不佳,宁愿这样做。
感谢任何帮助!
for 循环在看到任何白色space 时分裂,例如 space、制表符或换行符。所以,在循环之前需要IFS,(关于...的问题很多)
IFS=$'\n' && for i in $(ncftpls -l 'ftp://theftpserver/path/to/files' | awk '{print , }'); 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
我认为更好的方法是使用 while not for,所以
ls -l | while read i
do
echo $i | awk '{print , }'
#split them if you want
x=echo $i | awk '{print }'
y=echo $i | awk '{print }'
done