【问题标题】:Automatically feed input to Linux command line [duplicate]自动将输入输入到 Linux 命令行 [重复]
【发布时间】:2013-04-08 06:22:24
【问题描述】:

如果我有一个提示输入 2 个或更多输入的 linux 命令,如何通过在命令行中定义这些输入将其传递给提示?您可以在命令后面添加一些东西来执行此操作吗?

在下面的示例中,如何运行命令并将用户名和密码传递给它,而无需在系统要求时输入它们?

要求用户名和密码的示例命令

git clone https://github.com/username/repo.git 

只是一个例子,请不要建议使用 ssh 而不是 http 进行 git clone,或者在命令中暴露密码是不安全的

【问题讨论】:

  • man expect ...如果没有安装:sudo apt-get install expect
  • 请注意,具体的命令是相关的,因为有些使用标准输入和输出(通常可以通过通常的 shell 方式重定向),而另一些,如 git 使用的 ssh,使用终端。我几乎可以肯定有一些“终端”可以支持您的使用(也许期望可以做到这一点),但它总是一个糟糕的拐杖。这就是几乎所有特定的交互式程序(例如 vi)都有非交互式对应程序(例如 sed)并且人们在每种特定情况下(例如 git)回答“但不要那样做”的原因。
  • 啊,here on superuser 是一个如何使用 expect 的指令。可以预见的是,以“但不要那样做”结尾;-)。所以这是一个重复但在另一个 SE 上。

标签: linux git bash ubuntu


【解决方案1】:

注意:Git 要求您使用 git 令牌而不是密码。

empty 是一个实用程序,它提供了一个简单的界面来执行和/或 在伪终端会话下与进程交互。

这个工具在编写 shell 脚本时绝对有用 sed 用于与 telnet 或 FTP 等交互式程序进行通信。

在某些情况下,空可以替代 TCL/expect 或其他 类似的编程工具。

将下面的代码复制到您的脚本文件中。

通过从命令行提供以下参数(如您所要求的那样)使其可执行并运行脚本:

  • Git repo URI(作为第一个参数)
  • Git 用户名(作为第二个参数)
  • Git 用户令牌(作为第三个参数)

例子:

假设你的脚本文件名是:git_clone.sh:

./git_clone.sh  <GIT_REPO_URI>  <GIT_USERNAME>  <GIT_USER_TOKEN>
#!/bin/bash
git_repo="${1}"
git_user="${2}"
git_token="${3}"

empty -f -i in.fifo -o out.fifo -pempty.pid  git clone  

empty -w -i out.fifo -o in.fifo sername  "${git_user}\n"
empty -w -i out.fifo -o in.fifo assword  "${git_token}\n"

exit 0

有关empty 的更多详细信息,请参阅其手册: http://manpages.ubuntu.com/manpages/bionic/man1/empty.1.html

注意:empty 命令需要通过安装empty-expect 包才能使用。

要在 Ubuntu 上安装,您可以运行:

apt update;
apt install -y empty-expect

【讨论】:

  • empty: command not found 为什么会出现这个错误?
  • @ChitturiSaiSuman,请确保您已安装空包。示例如何在基于 Ubuntu 的发行版上安装,运行:sudo apt update; sudo apt install empty-expect
  • 嗨,Ubuntu 20.04 LTS (Ubuntu Focal) 上似乎没有 'empty-expect' 包。
  • @ChitturiSaiSauman,我没有 Ubuntu 20.04,但我建议如下:谷歌它,并分享你在我之前的评论中运行命令时得到的输出。谢谢。
  • ``` sudo apt install -y empty-expect 正在读取包列表...完成构建依赖关系树正在读取状态信息...完成 E:无法找到包空预期 ``跨度>
【解决方案2】:

下,您可以使用script

script 将生成一个tty,您可以使用coproc 下与之交互。这可以在不需要expect 的情况下完成:

NAME
      script - make typescript of terminal session

SYNOPSIS
      script [options] [file]

DESCRIPTION
      script  makes  a  typescript  of everything on your terminal session.
      The terminal data are stored in raw form to the log file and information
      about timing to another (optional) structured log file. The timing
      log file is necessary to replay the session later by scriptreplay(1) and to
      store additional information about the session.

演示

coproc script -f /dev/null

可以返回:

[1] 2103233

这会启动一个子shell,你可以与之交互,

while read -t 0 -u ${COPROC[0]};do
    read -t .02 -ru ${COPROC[0]} line
    echo "$line"
done

应该产生类似的东西:

Script started, output log file is 'typescript'.
user@hostname:~$

然后

echo >&${COPROC[1]} ssh user@target
while [ ! "$line" ] || [ "${line//*password*}" ];do
    read -t .02 -ru ${COPROC[0]} line
    echo "$line"
done
echo >&${COPROC[1]} TheStrongPasswordInClear
while [ ! "$line" ] || [ "${line//*\$*}" ];do
        read -t .02 -ru ${COPROC[0]} line
    echo "$line"
done

在那里,你可以看到很多类似的行

ssh user@target
user@target's password:

Linux target 5.00.0-0-amd64 # Distro ...
issue.net content...
Last login: Sun Dec 19 12:23:37 2021 from somewhere

user@target:~$ 

从那里,您可以:

getres() {
    while read -t 0 -u ${COPROC[0]};do
        read -t .02 -ru ${COPROC[0]} line
        echo "$line"
    done
}

echo >&${COPROC[1]} uptime
getres
uptime
12:38:38 up 21 days,  3:52, 122 users,  load average: 3.20, 2.19, 1.59

最后

echo >&${COPROC[1]} exit  
getres 
exit
logout
Connection to target closed.

完整的可执行 脚本

这在bash 5.1.4(1)-release 下运行,在GNU/Debian Linux 11.2 上运行:

#!/bin/bash
line='' Debug=false

exp1() { # Collect input by bytes, until expected string (1st arg)
    local char attended="*${1}"
    line=
    IFS= read -d '' -ru "${COPROC[0]}" -t 2 -n 1 line
    while IFS= read -d '' -ru "${COPROC[0]}" -t .02 -n 1 char;do
        line+="$char"
        case "$line" in
            *$1 ) $Debug && echo "GOOD ${line@A} match ${attended@A}"
                  return 0;;
        esac
    done
    $Debug && echo "BAD: ${line@A}"
    return 1
}
expect() { # expect <Expected String after> <Command> [switches] [args]
    local expectStr="$1" maxErr=5
    shift
    [ "$1" ] && echo >&"${COPROC[1]}" "$@"
    while ! exp1 "${expectStr}" && ((maxErr--));do sleep .2;done
}
getAns() { # getAns <ResultVar> <Command> [switches] [args]
    local -n res=$1
    res=''
    shift
    local req="$*" maxErr=5
    echo >&"${COPROC[1]}" "$req"
    exp1 "$req"$'\r\n'
    while ! exp1 "$ " && ((maxErr--));do res+="$line" ;sleep .2 ;done
    res+="${line%$'\r\n'*}"
}
read -rp target:\  target
read -rsp password:\  pass
echo "${pass//?/*}"

coproc TERM=none script -f /dev/null
IFS= read -ru "${COPROC[0]}" line &&
    $Debug && echo "1 >>> $line <<<"

expect '$ '
expect 'password: ' ssh "$target"
expect '$ ' "$pass"

getAns ut uptime
# shellcheck disable=SC2154 # referenced but not assigned (ut ??)
echo "${ut@A}"

expect '$ '  exit

运行示例:

target: user@target
password: ************
ut=' 11:06:20 up 5 days, 2:19, 22 users, load average: 0.74, 1.13, 1.27'

您可以在我的网站上找到此脚本:expectScr.shexpectScr.sh.txt,可以获取源代码

【讨论】:

【解决方案3】:

不知道你有没有试过。但这在我们执行任何 sudo cmd 并需要输入密码的情况下很有用。你可以试试这个。

但我认为您至少必须提供用户名。

例如:

sudo -S <<< "password" sudo yum -y update 

在你的情况下,应该是这样的:

sudo -S <<< {password} git clone https://github.com/{username}/repo.git

【讨论】:

    【解决方案4】:

    “expect”包就是为这种事情而构建的。 如果您安装它,请查看“autoexpect”。

    例子:

    autoexpect
    # Output: autoexpect started, file is script.exp
    
    # Login with user/pass with ssh - just to test
    ssh -o PubkeyAuthentication=no myuser@myhost
    <type-password>
    <command>
    <command>
    exit
    
    # Now exit once more to exit autoexpect
    # Output: autoexpect done, file is script.exp
    

    接下来是编辑 script.exp 并清理它。 这方面有大量文档。

    【讨论】:

    • Hmm... 对this answer 的评论似乎表明期望在这里不起作用,因为 ssh 使用终端设备而不是 stdin/stdout。我不确定期望能做到这一点。可能是因为这些是有趣的案例。你能举个例子吗?
    【解决方案5】:

    我想要赏金,但我不能以 dup 身份关闭,因为答案在不同的 SE 上。

    引用the answer on superuser:

    使用程序expect,它的设计正是为了满足您的需求,在我们这个时代之前,用户已经感受到了这一点,因为它的man page 声明:

    连接到其他网络或 BBS(例如 MCI Mail、CompuServe)。

    Compuserve,那是在法国大革命之前还是之后?无论如何。

    spawn "git clone ssh://git@domain.com/myproject.git"
    expect "Enter passphrase for key..." { send "myPassword\r" }
    read -p "enter..."
    

    也许最后一行是多余的。

    Ceterum censeo:别那样做。

    【讨论】:

      【解决方案6】:

      也许是这样

      {
        echo user
        echo pass
      } | git clone https://github.com/username/repo.git
      

      ref

      【讨论】:

      • 如果git 从标准输入读取密码,这将起作用,但如果它从/dev/tty 读取密码则不起作用(正如许多密码提示应用程序所做的那样)。我不知道git 在这方面是如何工作的。
      【解决方案7】:

      根据您想要这样做的原因,您可能想探索在没有密码的情况下使用 github 存储库的方法:

      https://help.github.com/articles/managing-deploy-keys

      【讨论】:

        猜你喜欢
        • 2013-12-12
        • 2020-04-11
        • 1970-01-01
        • 2014-03-29
        • 2013-02-25
        • 2014-02-02
        • 2020-10-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多