0

我在远程服务器上运行大量模拟(通过 ssh)。这些模拟的结果以 .tar 档案的形式存储在此远程服务器上的档案目录中。

我想做的是编写一个 bash 脚本,该脚本通过 ssh 连接到远程服务器,并将每个 .tar 存档中所需的输出文件提取到本地硬盘驱动器上的单独文件夹中。

这些文件夹应该与文件所在的 .tar 文件同名(举个例子,假设模拟 1 的输出存储在远程服务器上的存档 S1.tar 中,我想要所有的 '.dat' 和此 .tar 存档中的“.def”文件将被提取到我本地驱动器上的目录 S1 中)。

对于提取本身,我正在尝试:

for f in *.tar; do
(
    mkdir ../${f%.tar}
    tar -x -f "$f" -C ../${f%.tar} "*.dat" "*.def"
)
done
wait

每个 .tar 文件大约 1GB,而且数量很多。所以下载所有东西需要太多时间,这就是为什么我只想提取必要的文件(参见上面代码中的扩展名)。

现在,当我的本地驱动器上有 .tar 文件时,代码可以完美运行。但是,我想不通的是如何在无需先从服务器下载所有 .tar 档案的情况下做到这一点。

当我第一次通过 连接到远程服务器时ssh username@host,终端会停止脚本并连接到服务器。

顺便说一句,我在 VS Code 中执行此操作并通过我的 MacBook 上的终端运行脚本。

我希望我已经描述得足够清楚了。谢谢您的帮助!

4

1 回答 1

0

tar通过 SSH 使用文件名流式传输返回的结果

要获取您希望从.tar文件中检索的数据,您需要将结果传递tar给带有--to-command选项的命令字符串。在下面的示例中,我们将运行三个命令。

# Send the files name back to your shell
echo $TAR_FILENAME

# Send the contents of the file back
cat /dev/stdin

# Send EOF (Ctrl+d) back (note: since we're already in a $'' we don't use the $ again)
echo '\004'

在您的 shell 中捕获信息后,我们就可以开始处理数据了。这是一个三步过程。

  1. 获取文件名
    • 请注意,在这段代码中,我们根本不处理目录(只是将它们剥离;即dir/1.dat -> 1.dat
    • 您可以编写代码通过用空格替换正斜杠/并迭代每个目录名称来为文件创建目录,但这似乎超出了范围。
  2. 检查 EOF(文件结尾)
  3. 将内容添加到文件
# Get the files via ssh and tar
files=$(ssh -n <user@server> $'tar -xf <tar-file> --wildcards \'*\' --to-command=$\'echo $TAR_FILENAME; cat /dev/stdin; echo \'\004\'\'')

# Keeps track of what state we're in (filename or content)
state="filename"
filename=""

# Each line is one of these:
#  - file's name
#  - file's data
#  - EOF
while read line; do
  if [[ $state == "filename" ]]; then
    filename=${line/*\//}
    touch $filename
    echo "Copying: $filename"
    state="content"
  elif [[ $state == "content" ]]; then
    # look for EOF (ctrl+d)
    if [[ $line == $'\004' ]]; then
      filename=""
      state="filename"
    else
      # append data to file
      echo $line >> <output-folder>/$filename
    fi
  fi
# Double quotes here are very important
done < <(echo -e "$files")

替代方案:tar+scp

如果上面的例子看起来过于复杂,那就是它正在做的事情。更多地接触磁盘并需要分离 ssh 连接的另一种方法是将您需要的文件从.tar文件中提取到一个文件夹中,然后scp将该文件夹返回到您的工作站。

ssh -n <username>@<server> 'mkdir output/; tar -C output/ -xf <tar-file> --wildcards *.dat *.def'
scp -r <username>@<server>:output/ ./

击穿

首先,我们将创建一个地方来保存我们输出的文件。如果您已经知道它们所在的文件夹,则可以跳过此步骤。

mkdir output/

然后,我们会将匹配的文件提取到我们创建的这个文件夹中(如果您不希望它们位于不同的文件夹中,请删除该-C output/选项)。

tar -C output/ -xf <tar-file> --wildcards *.dat *.def

最后,现在我们再次在我们的机器上运行命令,我们可以运行scp以重新连接到远程机器并拉回文件。

scp -r <username>@<server>:output/ ./
于 2020-06-12T19:38:52.080 回答