Я хотел бы 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
в терминале. Когда cat
awaits 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