Использование интерактивной опции cp для сохранения текста из stdin

Использование интерактивной опции cp для сохранения текста из stdin

В интерактивном скрипте оболочки я хотел бы сохранить вывод команды в файл, как в

$ echo "Hello, World" > test.txt

но не допустить перезаписи test.txt, если он уже существует. Поэтому я подумал, что было бы хорошей идеей использоватьсрс интерактивной опцией (ср -i) для проверки существования целевого файла. Я попробовал это:

$ echo -n "Hello" | cp -i /dev/stdin test.txt 

Это записывает «Hello» в test.txt, если test.txt еще не существует, но прерывает копирование, если test.txt существует, поскольку cp считывает ответ на вопрос о том, перезаписывать или нет, только из этого канала.

Однако, это

$ cp -i <(echo "World") test.txt
cp: overwrite 'test.txt'? y
'/proc/self/fd/11' -> 'test.txt'

работает так, как и задумано, cp, похоже, берет filedesriptor подпроцесса в качестве источника и копирует его в test.txt, и я просто не знаю, почему.

Есть ли какие-нибудь идеи, объяснения или лучшие способы сделать это?

решение1

Используйте другой файловый дескриптор вместо/dev/stdin

echo Hello | { cp -i /dev/fd/5 test.txt 5<&0 </dev/tty; }

Или, все еще можно написать скрипт через yes(1)

{ echo Hello | { cp -i /dev/fd/5 test.txt 5<&0 <&4; }; } 4<&0

В обоих вариантах дополнительные { ... }параметры cp -i ...нужны только в zsh, чтобы обойти его нестандартность.мультиосособенность.

Это должно работать в любой стандартной оболочке и любой системе, которая поддерживает /dev/fd/Nфайлы, за исключением комбинации Linux + ksh93, которая не будет работать, поскольку ksh93 реализует каналы с сокетами Unix, которые в Linux нельзя открыть /dev/fd/N(даже не echo | cat /dev/stdinбудут работать).

Вы echo -n "Hello" | cp -i /dev/stdin test.txtфактически затрете файл, если вместо этого "Hello"вы поместите его "You suck!"туда. Это одна из причин, почему вам не следует полагаться на cp -i.

решение2

Такие оболочки, как bashуже могут защищать от перезаписи файлов с помощью перенаправления

set -o noclobber
echo hello >world
echo hello >world
-bash: world: cannot overwrite existing file

Если вы хотите иметь возможность спрашивать пользователя перед перезаписью, я бы использовал что-то вроде этого вместо noclobberнастройки

#!/bin/bash

# Define function sureYN  [<prompt>]  <target>
sureYN() {
    local prompt="$1" target="$2" yn='y'
    [[ -z "$target" ]] && { target="$prompt"; prompt="Overwrite $target"; }

    [[ -f "$target" && -t 0 ]] && read -p "$prompt (y/n)? " yn >&2
    [[ "$yn" =~ ^[Yy] ]]
}

sureYN /tmp/first && cp -fp /etc/hosts /tmp/first
sureYN "Can I replace /tmp/second" /tmp/second && echo this is the second >/tmp/second

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