使用以下命令检查远程目录中特定类型的文件时出现错误。要求是获取特定文件的计数。
file_exists=$(sftp $FTP_UNAME@$FTP_HOST ls *$FILE_ID*.txt | wc -l)
这写得不好吗?请帮忙...
Below is the Usage Tip -
usage: sftp [-1246aCfpqrv] [-B buffer_size] [-b batchfile] [-c cipher]
[-D sftp_server_path] [-F ssh_config] [-i identity_file] [-l limit]
[-o ssh_option] [-P port] [-R num_requests] [-S program]
[-s subsystem | sftp_server] host
sftp [user@]host[:file ...]
sftp [user@]host[:dir[/]]
sftp -b batchfile [user@]host
答案1
sftp
很难在脚本中可靠地使用。您可以使用某些编程语言的 SFTP 模块来代替。以 perl 为例Net::SFTP::Foreign
:
perl -MNet::SFTP::Foreign -le '
($host, $dir, $id) = @ARGV;
$s = Net::SFTP::Foreign->new($host, autodie => 1, fs_encoding => latin1);
print scalar @{
$s->ls($dir, names_only => 1, wanted => qr/\Q$id\E.*\.txt\z/s)
}' -- "$FTP_UNAME@$FTP_HOST" . "$FILE_ID"
将报告其名称包含并以您的登陆目录$FILE_ID
结尾的文件数量,无论可能包含什么(甚至是空格等可能会出现问题的内容)以及文件名包含的任何内容(甚至是换行符,这可能会成为问题) 。.txt
$FILE_ID
;
sftp
wc -l
(latin1
编码不尝试进行 UTF-8 解码并使用文件路径中的任意字节值)。
要获取 shell 数组中的文件列表,请使用zsh
:
files=( ${(0)"$(
perl -MNet::SFTP::Foreign -l0 -e '
($host, $dir, $id) = @ARGV;
$s = Net::SFTP::Foreign->new($host, autodie => 1, fs_encoding => latin1);
print for @{
$s->ls($dir, names_only => 1, wanted => qr/\Q$id\E.*\.txt\z/s)
}' -- "$FTP_UNAME@$FTP_HOST" . "$FILE_ID")"}
)
对于 bash 4.4+:
readarray -td '' files < <(
perl -MNet::SFTP::Foreign -l0 -e '
($host, $dir, $id) = @ARGV;
$s = Net::SFTP::Foreign->new($host, autodie => 1, fs_encoding => latin1);
print for @{
$s->ls($dir, names_only => 1, wanted => qr/\Q$id\E.*\.txt\z/s)
}' -- "$FTP_UNAME@$FTP_HOST" . "$FILE_ID")
尽管您失去了 的退出状态perl
。
答案2
如中所述手动的,sftp-b
(1) 除非给出(批处理模式)参数,否则将进入交互模式。将命令通过管道传输到sftp,指定 的特殊文件名-
,例如:
printf "ls\n" | sftp -b- server.example.com
您的命令包含不带引号的通配符,这些通配符在路径名扩展期间由 shell 解释,并应用于本地当前目录(这可能是不希望的),因此需要引用该参数。此外,您需要将参数传递-1
给sftp的命令,ls
如果你想计算它输出的行数。
最后,命令的输出行ls
包括交互式提示行和命令本身,因此计数需要减一。有多种方法可以实现这一点,例如在类似的结构中使用算术扩展
printf "%d\n" $(( $( ... ) - 1))
附录:正如 @Stéphane Chazelas 所说,由于 OP 计算文件的方式,该解决方案将出现包含换行符的文件名问题(诚然,这极不可能,但理论上是可能的)厕所;有一个完整的问题及其答案为什么不解析输出LS(效用),以及该怎么做,结论与 Stéphane 类似。此外,厕所不区分目录和文件 - 它很重要线,包含目录和文件。同样,模式作为参数传递给sftp如果包含空格,则命令ls
将不起作用。它可以在引用中引用,但它增加了一层复杂性:
printf "ls -1 *\"$FILE_ID\"*.txt\n" | ...
我的答案背后的想法更具教育意义——回答“这写得不对吗?”的问题。而不是提供一个在所有情况下都有效的解决方案。