0

I would like cp to prompt before overwriting so I am using -i.

(I might sometimes use an alias for cp, or similar, so cp always occurs with -i).

I may want to say overwrite all. I know that's the default but since i'm using -i I don't see that.

I want to easily be able to make it do 'yes' to all, or 'no' to all.

I am not asking how to bypass an alias, I want the -i.

Here is my attempt at forcing yes, given -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$ 

So I manage to force 'y' to all but then I don't get new lines.

When I try yes ''| then it doesn't send a yes.

I'd also like to be able to pass an 'n'/'no' too.

And I may have many files so I'm not looking to manually type yEnter or nEnter for each file.

I don't mind a solution that doesn't involve the yes command.

0

3 Answers 3

1

This is not as easy as it may seem.

Analysis

When running cp -i and answering it prompts interactively, the newline you get after typing yEnter comes from the line discipline. The line discipline echoes y and the newline.

You can observe this mechanism by running sole cat in a terminal. When cat awaits input, you can type a long line and even erase characters (with Backspace) or the whole line (with Ctrl+u); everything you see is handled by the line discipline, cat just sits there without any input. Only when you hit Enter (or Ctrl+m, or Ctrl+j), cat gets the line and prints it. The newline after what you typed is from the line discipline, the newline after what cat printed is from cat.

Or you can type something and hit Ctrl+d to send it to cat without a newline. Then there will be no newline after what you typed and no newline after what cat printed.

Similarly, when prompted by cp -i, you can interactively type yCtrl+dCtrl+d (why twice? here), cp will accept y and you will see y echoed by the line discipline, but no newline (because you did not type one). cp itself does not print a newline here. Normally (i.e. when you do type Enter) what you see looks right (i.e. with newlines in the right places) because of the line discipline. We can say cp expects a line discipline that injects newline characters where appropriate and thus makes the output look nice.

The point is there is a line discipline between your keyboard and cp -i, it echoes what you type, including a newline upon Enter.

In your yes | cp -i …, cp gets input almost as if you typed yEnter via a line discipline, but this time there is nothing like a line discipline that would echo what enters cp. This is the reason you observed no newlines (and no y characters).

In the case of yes '' | cp -i …, the newlines after not overwritten were actually printed by cp. What's missing is a newline before each not overwritten. Without yes, if you just hit Enter in response to the prompt, you would see not overwritten in a separate line.


Towards solution

To get what you want, you need something that echoes the input that goes into cp. At first glance it seems it may be an actual line discipline (few ideas here: How to trick a command into thinking its output is going to a terminal; note we don't want to trick cp, we want a "side effect" of having a terminal) or tee between yes and cp, like this:

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

The above will not work well because yes generates its output immediately and as much as possible, it's like a user who mashes yEnter no matter if prompted or not. Echoing this makes the output look way worse than what you posted in the question.

Even if you knew in advance you needed just one yEnter, using echo y instead of yes would also not work well, because most likely the input would be seen and printed (by the added line discipline or by tee) before cp prints its prompt.


Solution

A proper solution is to run cp -i … with additional pty, but only give it input when prompted. expect(1) can do it. This is a quick and dirty expect script:

#!/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
   }
}

Users with localized cp should adjust the "overwrite *\\?" pattern.

Be advised I have little experience with expect, the script may be sub-optimal or even somewhat flawed. Treat it as a proof of concept. Save the script as cpx in a directory in your $PATH, make it executable (chmod +x cpx) and use like this:

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

In practice it may be good to define shell aliases:

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

and use them like this:

cpy ?.? smalls
# or
cpn ?.? smalls
-1

Plenty of ways to bypass the alias to use native cp:

  • Use the command builtin: command cp
  • Use the full path of the command: /bin/cp
  • Add a \ anywhere in the command name, for example: \cp
  • Quote the command: "cp" or 'cp'
5
  • -1 why on earth are you telling me how to bypass an alias, I very clearly never asked such a thing at all
    – barlop
    Commented May 24, 2019 at 21:40
  • I have now added this line I am not asking how to bypass an alias, I want the -i. making it even more clear and obvious.
    – barlop
    Commented May 24, 2019 at 21:42
  • And if I wanted to ask how to bypass an alias, i'd have asked that, without any of the other stuff, but I didn't.
    – barlop
    Commented May 24, 2019 at 21:43
  • Sorry, I thought you wanted a practical solution.
    – xenoid
    Commented May 24, 2019 at 22:46
  • a solution to the question I asked, whose first line includes the words "I am using -i."
    – barlop
    Commented May 24, 2019 at 22:48
-1

You can use 'yes |' in front of your code.

yes | cp -i ?.? smalls
1
  • no that's not a solution, the question itself mentions that
    – barlop
    Commented Dec 12, 2023 at 17:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .