我如何才能让 yes 命令强制覆盖并使用新行来执行?

我如何才能让 yes 命令强制覆盖并使用新行来执行?

我想cp在覆盖之前提示,因此我使用-i

cp(我有时可能会使用或类似的别名,因此cp总是与 一起出现-i)。

我可能想说覆盖全部。我知道这是默认设置,但由于我正在使用,所以-i我看不到它。

我希望能够轻松地让它对所有答案都回答“是”,或者对所有答案都回答“否”。

我不是问如何绕过别名,我想要-i

这是我在给定 的情况下强制“是”的尝试-i

~$ mkdir test1
~$ cd test1
~/test1$ mkdir smalls
~/test1$ touch a.a
~/test1$ touch b.b
~/test1$ cp -i ?.? smalls
~/test1$ cp -i ?.? smalls
overwrite smalls/a.a? (y/n [n]) y
overwrite smalls/b.b? (y/n [n]) y
~/test1$ yes|cp -i ?.? smalls
overwrite smalls/a.a? (y/n [n]) overwrite smalls/b.b? (y/n [n]) ~/test1$ 
~/test1$ 
~/test1$ yes ''|cp -i ?.? smalls
overwrite smalls/a.a? (y/n [n]) not overwritten
overwrite smalls/b.b? (y/n [n]) not overwritten
~/test1$ 

因此,我设法将“y”强制应用于所有内容,但却没有得到新行。

当我尝试yes ''| 时,它并没有发送“是”的答复。

我也希望能够传递“n”/“no”。

而且我可能有很多文件,所以我不想手动输入yEnternEnter输入每个文件。

我不介意不涉及命令的解决方案yes

答案1

这并不像看上去那么容易。

分析

运行cp -i并回答时,它会以交互方式提示,输入后得到的换行符yEnter来自行规。行规会回显y并显示换行符。

cat您可以通过在终端中运行 sole 来观察此机制。当cat等待输入时,您可以输入一长行,甚至可以删除字符(使用Backspace)或整行(使用Ctrl+ u);您看到的所有内容都由行规程处理,cat只是停留在那里而没有任何输入。只有当您按下Enter(或Ctrl+ m,或Ctrl+ j)时,cat才会获取该行并打印它。您输入的内容后的换行符来自行规程,cat打印内容后的换行符来自cat

或者您可以输入一些内容,然后按Ctrl+d将其发送到cat而不换行。这样,您输入的内容后就不会有换行符,cat打印的内容后也不会有换行符。

类似地,当出现提示时cp -i,您可以交互地输入yCtrl++ dCtrld为什么是两次?这里)cp将接受y,您将看到y行规程的回显,但没有换行符(因为您没有输入换行符)。cp本身不会在此处打印换行符。通常(即当您输入时Enter)您看到的内容看起来是正确的(即在正确的位置有换行符),这是因为行规程。我们可以说cp期望行规程在适当的位置插入换行符,从而使输出看起来不错。

重点是键盘和 之间的换行符cp -i,它会响应您输入的内容,包括 上的换行符Enter

在您的 中yes | cp -i …cp输入几乎就像您yEnter通过行规则输入一样,但这次没有像行规则那样可以回显输入的内容。这就是您没有观察到换行符(也没有字符)cp的原因。y

在 的情况下yes '' | cp -i …, 之后的换行符not overwritten实际上是由 打印的cp。缺少的是每个 之前的换行符not overwritten。如果没有yes,如果您只是Enter响应提示而点击 ,您将not overwritten在单独的行中看到。


走向解决方案

为了得到你想要的东西,你需要一些东西来回应输入的内容cp。乍一看,它似乎可能是一个真正的生产线纪律(这里有一些想法:如何欺骗命令,让其认为其输出将发送到终端;请注意,我们不想欺骗cp,我们想要一个拥有终端的“副作用”)或teeyes和之间cp,如下所示:

# both flawed
yes | socat STDIO EXEC:'cp -i …',pty
yes | tee >/dev/tty | cp -i …

上面的方法效果不佳,因为yes它会立即生成尽可能多的输出,就像一个用户yEnter不管是否提示都会乱七八糟一样。回显此方法会使输出看起来比您在问题中发布的内容更糟糕。

即使您事先知道只需要一个yEnter,使用echo y而不是也不会很好地工作,因为在打印其提示之前yes,输入很可能会被看到并打印(通过添加的行规则或tee) 。cp


解决方案

一个合适的解决方案是使用额外的 pty 运行cp -i …,但只在提示时给它输入。expect(1)可以做到。这是一个快速而肮脏的expect脚本:

#!/usr/bin/expect -f

set str [lindex $argv 0]
spawn -noecho cp -i {*}[lrange "$argv" 1 end]
while 1 {
   expect {
      "overwrite *\\?" { send "$str\r" }
      eof exit
   }
}

有本地化需求的用户cp请自行调整"overwrite *\\?"模式。

请注意,我对 经验不足expect,该脚本可能不是最理想的,甚至有些缺陷。将其视为概念证明。将脚本保存为cpx目录中的$PATH,使其可执行(chmod +x cpx)并按如下方式使用:

cpx y ?.? smalls
# or
cpx n ?.? smalls

在实践中,定义 shell 别名可能会很好:

alias cpy='cpx y'
alias cpn='cpx n'

并像这样使用它们:

cpy ?.? smalls
# or
cpn ?.? smalls

答案2

有很多方法可以绕过别名来使用 native cp

  • 使用内置命令:command cp
  • 使用命令的完整路径:/bin/cp
  • 在命令名称的任何位置添加 \,例如:\cp
  • 引用命令:"cp"'cp'

答案3

您可以在代码前使用“yes |”。

yes | cp -i ?.? smalls

相关内容