【问题标题】:scp multiple arguments of bash scriptscp bash脚本的多个参数
【发布时间】:2023-03-04 18:28:01
【问题描述】:

我正在尝试使用scp 从远程服务器复制多个文件。

我可以为script file_number 的单个参数成功地做到这一点

script 在哪里:

#!/bin/bash
echo Insert your username:
read user
scp $user@server:/path/run$1*.lz4 ./
lz4 -mdv --rm run$1*.lz4 

我所有文件的格式为:runXXXXsubY.lz4

这样我可以复制所有具有XXXX==file_number 的文件,但我想传递多个参数,并复制所有这些文件,例如script 1 2 复制所有带有xxxx==1XXXX==2 的文件。

我试过了:

scp $user@server:/path/run"$@"*.lz4 ./ 

但是$@ 会在没有附加*.lz4 的情况下展开

感谢您在正确方向上的任何帮助。

谢谢

【问题讨论】:

  • 它充满了危险和引用问题,但你可以这样做scp $(printf "$user@server:/path/run%s.lz4 " "$@") ./。使用 xargs 会更好。
  • 您最好使用一个简单的 for 循环为每个文件调用一次 scp。与多次调用相比,使用多个参数调用 scp 并没有太多好处。
  • @WilliamPursell for 循环的问题在于它要求输入密码的次数与参数的次数一样多。这是我想避免的。
  • 你应该设置你的 ssh 密钥,这样就不需要密码了。
  • 如果您需要复制很多个文件,我会看看如何在主模式下运行ssh,以便每个scp可以重复使用相同的经过身份验证的连接每次传输,而不必为每个文件重新验证。

标签: bash shell arguments


【解决方案1】:

IMO 最好的选择是一个简单的 for 循环:

for xxx; do
    scp "$user@server:/path/run${xxx}.lz4" ./ 
done

如果您确实想运行单个scp(避免多次密码提示不是这样做的动机;避免多次密码提示的方法是设置您的 ssh 密钥,因此不需要密码),您可以使用xargs:

printf "$user@server:/path/run%s.lz4\0" "$@" | xargs -0 -J % scp % ./

这并不能保证单次调用,如果传递了足够多的参数以使参数字符串超出某些限制,xargs 将运行多次scp 调用,但这应该就足够了。

【讨论】:

    【解决方案2】:

    基本问题是,当 shell 扩展 $user@server:/path/run"$@"*.lz4 时,它不会为每个参数复制 $user:...*.lz4 部分,它只是盲目地添加参数列表——包括论点——进入中间。因此,如果 args 是 12,它本质上会扩展为:

    scp $user@server:/path/run"1" "2"*.lz4 ./ 
    

    ...所以$user@server:/path/run"1""2"*.lz4scp 的单独参数,这没有用。您可以做的是根据参数创建一个数组,然后使用 that 作为scp 的源列表。像这样的:

    sources=()
    for runNum in "$@"; do
        sources+=("$user@server:/path/run${runNum}*.lz4")
    done
    scp "${sources[@]}" ./
    

    然后对lz4 命令使用单独的循环:

    for runNum in "$@"; do
        lz4 -mdv --rm run${runNum}*.lz4
    done
    

    编辑:为避免多次验证,您可以打开一个主 SSH 连接并让所有 scp 传输捎带。这是一个示例,主要基于 Felix Rabe 的回答 here

    # Create the array of source file patterns to fetch
    sources=()
    for runNum in "$@"; do
        sources+=("$user@server:/path/run${runNum}*.lz4")
    done
    
    # Open master SSH connection:
    # (This is the only time you have to enter the password)
    sshSocket=~/"$user@server"
    ssh -M -f -N -S "$sshSocket" "$user@server"
    
    # Actually copy the files:
    scp -o ControlPath="$sshSocket" "${sources[@]}" ./
    
    # Close master connection:
    ssh -S "$sshSocket" -O exit "$user@server"
    

    【讨论】:

    • 这个解决方案仍然需要我为脚本中的每个参数输入密码。
    • @user17004502 我显然没有彻底测试那部分。在任何情况下,它都可以通过主 SSH 连接来修复,请参阅更新。
    【解决方案3】:

    为远程文件名构建模式的一种参数替换思想:

    $ fn="$@"
    $ echo scp "user@server:/path/run{${fn// /,}}*.lz4" ./
    

    假设$@ = 222 333 这会生成:

    scp user@server:/path/run{222,333}*.lz4 ./
    

    注意:一旦对格式满意,请删除echo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-30
      • 2022-10-23
      • 1970-01-01
      • 2022-10-23
      • 2021-11-04
      • 2012-04-17
      • 1970-01-01
      • 2012-03-22
      相关资源
      最近更新 更多