как мне заставить команду 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 ''| , ответ «да» не приходит.

Мне бы также хотелось уметь передавать «н»/«нет».

И у меня может быть много файлов, поэтому мне не хочется вручную вводить данные yEnterдля nEnterкаждого файла.

Я не против решения, не связанного с командованием yes.

решение1

Это не так просто, как может показаться.

Анализ

При запуске cp -iи ответе на его запросы в интерактивном режиме новая строка, которую вы получаете после набора текста, yEnterисходит из дисциплины строки. Дисциплина строки отражается yи новая строка.

Вы можете наблюдать этот механизм, запустив sole catв терминале. Когда catawaits input, вы можете ввести длинную строку и даже стереть символы (с помощью Backspace) или всю строку (с помощью Ctrl+ u); все, что вы видите, обрабатывается дисциплиной строки, catпросто остается там без какого-либо ввода. Только когда вы нажимаете Enter(или Ctrl+ m, или Ctrl+ j), catполучает строку и печатает ее. Новая строка после того, что вы набрали, идет от дисциплины строки, новая строка после того, что catнапечатано, идет от cat.

Или вы можете набрать что-то и нажать Ctrl+ d, чтобы отправить это catбез новой строки. Тогда не будет новой строки после того, что вы набрали, и не будет новой строки после того, что catнапечатали.

Аналогично, при появлении запроса cp -iвы можете интерактивно ввести yCtrl+ dCtrl+ d(зачем дважды?здесь), 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, мы хотим «побочный эффект» наличия терминала) или teeмежду yesи cp, например так:

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

Вышеуказанное не будет работать хорошо, потому что yesгенерирует свой вывод немедленно и насколько это возможно, это как пользователь, который давит yEnterнезависимо от того, подсказано ему или нет. Повтор этого делает вывод намного хуже, чем тот, что вы разместили в вопросе.

Даже если бы вы заранее знали, что вам нужен только один yEnter, использование echo yвместо yesтакже не сработает, поскольку, скорее всего, ввод будет увиден и выведен на печать (дисциплиной добавленной строки или tee) до того, как cpвыведет свое приглашение.


Решение

Правильное решение — запустить cp -i …с дополнительным pty, но давать ему входные данные только при запросе. 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

На практике может быть полезно определить псевдонимы оболочки:

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

Связанный контент