AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 760629
Accepted
Daniel Krajnik
Daniel Krajnik
Asked: 2023-11-04 23:49:50 +0800 CST2023-11-04 23:49:50 +0800 CST 2023-11-04 23:49:50 +0800 CST

对于具有自定义端口的服务器循环(for i in "user1@server1 -p 12345" "user2@server2 -p 54321" ...; do)

  • 772

我正在尝试通过 ssh 在一系列服务器上运行命令。我最近更改了 ssh 端口以避免互联网扫描仪,但这破坏了我的脚本。有谁知道在 for 循环中为每个 user@server 条目指定不同端口的“简单方法”?

for i in '[email protected] -p 12345' '[email protected] -p 54321'
 do printf "\e[%sm%s\e[00m\n" 32 $i
 ssh $i crontab -l
done

第二行只是在输出之前打印服务器名称(为了可读性)。

它给我的不是幸福,而是:ssh: Could not resolve hostname server1.domain1.com -p 12345: Name or service not known

以前,当所有端口都是默认的 22 并且不需要指定时,它就可以工作。

shell
  • 5 5 个回答
  • 1757 Views

5 个回答

  • Voted
  1. Kenster
    2023-11-05T07:23:54+08:002023-11-05T07:23:54+08:00

    OpenSSH 的最新版本ssh(自 v7.7 起)(及其scp和sftp)将接受 URI 形式的目标。如果您愿意,可以将端口号指定为 URI 的一部分,例如“ssh://someuser@somehost:42”连接到端口 42。就 shell 而言,URI 的优点是它是单个字符串被关注到。所以你可以这样做:

    for i in 'ssh://[email protected]:12345' 'ssh://[email protected]:54321'
     do printf ...
     ssh "$i" ...
    done
    

    SSH URI 的一般形式是“ssh://user@host:port”。“用户”和“端口”部分都是可选的,如果您不需要为其指定值,则可以省略它们(以及“@”或“:”标点符号)。

    • 14
  2. Ángel
    2023-11-05T08:46:45+08:002023-11-05T08:46:45+08:00

    正确的方法是将其存储在配置中,而不是在每个连接上指定所有内容。

    在~/.ssh/config你可以有:

    Host server1.domain1.com  # When connecting to this
    User user1  # Use this user
    Port 12345  # with this port
    
    Host serv2  # We can also use a different, internal, name
    Hostname server1.domain1.com  # The actual hostname or IP it will use to connect
    User user2
    Port 54321
    

    然后ssh server1.domain1.com就会ssh serv2做正确的事™ 无需记住每台计算机使用的用户名或端口。对脚本和人类都有好处。

    如果您稍后更改端口,则可以在一个位置进行修改。

    还可以使用通配符,因此如果所有计算机的domain1.comsshd 都在端口 1234 上侦听,您可以将它们全部与 匹配Host *.domain1.com,而不必单独列出它们。

    • 14
  3. Best Answer
    Stéphane Chazelas
    2023-11-04T23:57:38+08:002023-11-04T23:57:38+08:00

    对于for可以循环多个变量的循环,请切换到zsh. 您已经zsh通过不引用变量来使用语法:

    # zsh
    for colour host port (
      green [email protected] 12345
      blue  [email protected] 54321
    ) {
      print -rP "%F{$colour}%B$host:$port%b%f"
      ssh -p $port $host 'crontab -l'
    }
    

    要循环参数列表,您可以使用具有多维数组的 shell,例如ksh93:

    # ksh93
    ssh_args=(
      (-p 12345 [email protected])
      (-p 54321 [email protected])
    )
    for i in "${!ssh_args[@]}"}; do
      printf '\e[1;32m%s\e[m\n' "${ssh_args[i][2]}"
      ssh "${ssh_args[i][@]}" 'crontab -l'
    done
    

    或者将包含字符串的数组元素与参数使用您知道字符串中不会出现的字符连接起来,然后将它们分开。zsh确实具有${(s[x])var}分裂特征。

    ksh 和 bash 也可以,但只能通过笨重的 split+glob 来实现,当您忘记在那里引用扩展时,会隐式调用它。您可以将其用作:

    # ksh93 / bash / yash / mksh / zsh --emulate ksh
    ssh_args=(
      -p:12345:[email protected]
      -p:54321:[email protected]
    )
    IFS=:; set -o noglob # tune your split+glob operator by specifying
                         # the separator and disabling globbing
    for joined_args in "${ssh_args[@]}"; do
      args=( $joined_args ) # invoke split+glob
      printf '\e[1;32m%s\e[m\n' "${args[2]}"
      ssh "${args[@]}" 'crontab -l'
    done
    

    这基本上就是您在方法中所做的,只是您使用空格而不是:分隔元素,但没有设置$IFS也没有禁用全局。

    事实上,你$i没有被分割可以通过$IFS设置为空字符串来解释,或者代码由 zsh 而不是 bash 运行,其中分割或通配符都不是在参数扩展时隐式完成的。

    在 zsh 中,如果您想要 IFS 分割,请使用,而$=var不是$var,如果您想要通配:$~var。bash 的$var类似于 zsh 的$=~var。所以在 zsh 中,你需要:

    # zsh
    ssh_args=(
      -p:12345:[email protected]
      -p:54321:[email protected]
    )
    IFS=:
    for joined_args in $ssh_args; do
      args=( $=joined_args ) # split on $IFS or better:
      args=( ${(s[:])joined_args} ) # split explicitly on : without
                                   # having to touch $IFS
      print -rP "%F{green}%B$host[-1]%b%f"
      ssh $args 'crontab -l'
    done
    

    一种可行的可移植方法sh是编写它:

    # sh / bash / dash / ksh / yash / zsh...
    while IFS=' ' read<&3 host port; do
      {
        printf '\33[1;32m%s\e[m\n' "$host:$port"
        ssh -p "$port" "$host" 'crontab -l'
      } 3<&-
    done 3<< 'EOF'
    user[email protected] 12345
    [email protected] 54321
    EOF
    

    省略-r选项以read允许值包含分隔符(此处为空格),方法是在它们前面加上反斜杠,如下所示:

    john\ doe@server1 1234
    

    但与其他方法相反,它不允许这些值包含换行符(对于用户、主机、服务名称或端口号来说可能不是问题)。

    另一种可移植的循环列表,所有列表都具有相同$n数量的元素,并且没有该限制,即将所有元素存储在位置参数中,并在循环中循环它们while [ "$#" -ge "$n" ]; do something with "$1" "$2"...; shift "$n"; done。所以在这里:

    # sh / bash / dash / ksh / yash / zsh...
    eval "$(
      printf "fg_%s='\33[3%sm' " \
        black 0 red     1 green 2 yellow 3 \
        blue  4 magenta 5 cyan  6 white  7
      printf "bg_%s='\33[4%sm' " \
        black 0 red     1 green 2 yellow 3 \
        blue  4 magenta 5 cyan  6 white  7
      printf "attr_%s='\33[%sm' " \
        reset '' bold     1 dim     2 italics 3 underline 4 \
        blink 5  standout 7 reverse 7 secure  8
    )"
        
    set -- \
      "$fg_green$attr_bold" [email protected] 12345 \
      "$bg_blue$fg_white"   [email protected] 54321
    
    while [ "$#" -ge 3 ]; do
      colour=$1 host=$2 port=$3
      printf '%s\n' "$colour$host:$port$attr_reset"
      ssh -p "$port" "$host" 'crontab -l'
      shift 3
    done
    
    • 10
  4. Kusalananda
    2023-11-05T20:08:12+08:002023-11-05T20:08:12+08:00

    在 POSIX shell 中,循环遍历两个列表的通用解决方案,在循环的每次迭代中使用一对元素(任一列表中的一个):

    #!/bin/sh
    
    # The list of port numbers
    set -- 123245 54321
    
    # Loop over the list of user@host strings
    for remote in \
        [email protected] \
        [email protected]
    do
        # Use "$remote" together with the port number in "$1", then shift
    
        printf 'Connecting to %s, port %s\n' "$remote" "$1"
    
        ssh -p "$1" "$remote" crontab -l
        shift
    done
    
    • 1
  5. Abdullah
    2023-11-07T03:27:57+08:002023-11-07T03:27:57+08:00

    多主机使用pdsh。广泛应用于拥有大量集群主机的数据中心。

    从 pdsh 文档 ..

    在主机 h0、h1、h2 上使用用户“foo”运行,在主机 h3、h5 上使用用户“bar”运行:

    pdsh -w foo@h[0-2],bar@h[3,5]
    

    https://code.google.com/archive/p/pdsh/wikis/UsingPDSH.wiki

    正如 Ángel 提到的,该工具与 ssh 配置文件一起使用。

    下面的完整示例..

    〜/ .ssh /配置

    Host server1
    Hostname server1
    User user1  
    Port 12345  
    
    Host server2
    Hostname server2
    User user2
    Port 54321
    

    现在简单运行

    pdsh -w server1,server2 crontab -l 
    
    • 0

相关问题

  • 这个命令是如何工作的?mkfifo /tmp/f; 猫/tmp/f | /bin/sh -i 2>&1 | 数控 -l 1234 > /tmp/f

  • FreeBSD 的 sh:列出函数

  • 有没有办法让 ls 只显示某些目录的隐藏文件?

  • grep -v grep 有什么作用

  • 如何将带有〜的路径保存到变量中?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve