从远程 ssh 服务器上的 tar 存档中提取某些文件
Extracting certain files from a tar archive on a remote ssh server
我在远程服务器上运行进行了多次模拟(通过ssh)。这些模拟的结果作为 .tar 存档存储在此远程服务器上的存档目录中。
我想做的是编写一个 bash 脚本,它通过 ssh 连接到远程服务器并从每个 .tar 存档中提取所需的输出文件到我本地的单独文件夹中硬盘。
这些文件夹应与文件来源的 .tar 文件同名(举个例子,假设模拟 1 的输出存储在存档 S1.tar 上远程服务器,我希望将此 .tar 存档中的所有“.dat”和“.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 上的终端编写脚本。
我希望我已经描述清楚了。感谢您的帮助!
通过 SSH
将 tar
的结果与文件名一起返回
要获取您希望从 .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 '[=10=]4'
在您的 shell 中捕获信息后,我们可以开始处理数据。这是一个三步过程。
- 获取文件名
- 请注意,在此代码中,我们根本不处理目录(只是将它们剥离;即
dir/1.dat -> 1.dat
)
- 您可以编写代码来为文件创建目录,方法是将正斜杠
/
替换为空格并遍历每个目录名称,但这似乎超出了此范围。
- 检查 EOF(文件结尾)
- 向文件添加内容
# 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 \'[=11=]4\'\'')
# 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 == $'[=11=]4' ]]; 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
最后,现在我们再次在我们的机器上 运行ning 命令,我们可以 运行 scp
重新连接到远程机器并拉回文件。
scp -r <username>@<server>:output/ ./
我在远程服务器上运行进行了多次模拟(通过ssh)。这些模拟的结果作为 .tar 存档存储在此远程服务器上的存档目录中。
我想做的是编写一个 bash 脚本,它通过 ssh 连接到远程服务器并从每个 .tar 存档中提取所需的输出文件到我本地的单独文件夹中硬盘。
这些文件夹应与文件来源的 .tar 文件同名(举个例子,假设模拟 1 的输出存储在存档 S1.tar 上远程服务器,我希望将此 .tar 存档中的所有“.dat”和“.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 上的终端编写脚本。
我希望我已经描述清楚了。感谢您的帮助!
通过 SSH
将tar
的结果与文件名一起返回
要获取您希望从 .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 '[=10=]4'
在您的 shell 中捕获信息后,我们可以开始处理数据。这是一个三步过程。
- 获取文件名
- 请注意,在此代码中,我们根本不处理目录(只是将它们剥离;即
dir/1.dat -> 1.dat
) - 您可以编写代码来为文件创建目录,方法是将正斜杠
/
替换为空格并遍历每个目录名称,但这似乎超出了此范围。
- 请注意,在此代码中,我们根本不处理目录(只是将它们剥离;即
- 检查 EOF(文件结尾)
- 向文件添加内容
# 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 \'[=11=]4\'\'')
# 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 == $'[=11=]4' ]]; 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
最后,现在我们再次在我们的机器上 运行ning 命令,我们可以 运行 scp
重新连接到远程机器并拉回文件。
scp -r <username>@<server>:output/ ./