在 shell 脚本中使用 sftp 计算远程位置的文件数

在 shell 脚本中使用 sftp 计算远程位置的文件数

使用以下命令检查远程目录中特定类型的文件时出现错误。要求是获取特定文件的计数。

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;sftpwc -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 解释,并应用于本地当前目录(这可能是不希望的),因此需要引用该参数。此外,您需要将参数传递-1sftp的命令,ls如果你想计算它输出的行数。

最后,命令的输出行ls包括交互式提示行和命令本身,因此计数需要减一。有多种方法可以实现这一点,例如在类似的结构中使用算术扩展

printf "%d\n" $(( $( ... ) - 1))

附录:正如 @Stéphane Chazelas 所说,由于 OP 计算文件的方式,该解决方案将出现包含换行符的文件名问题(诚然,这极不可能,但理论上是可能的)厕所;有一个完整的问题及其答案为什么不解析输出LS(效用),以及该怎么做,结论与 Stéphane 类似。此外,厕所不区分目录和文件 - 它很重要线,包含目录和文件。同样,模式作为参数传递给sftp如果包含空格,则命令ls将不起作用。它可以在引用中引用,但它增加了一层复杂性:

printf "ls -1 *\"$FILE_ID\"*.txt\n" | ...

我的答案背后的想法更具教育意义——回答“这写得不对吗?”的问题。而不是提供一个在所有情况下都有效的解决方案。

相关内容