Usando la opción interactiva de CP para guardar texto desde la entrada estándar

Usando la opción interactiva de CP para guardar texto desde la entrada estándar

En un script de shell interactivo, me gustaría guardar el resultado de un comando en un archivo como en

$ echo "Hello, World" > test.txt

pero evita que se sobrescriba test.txt si ya existe. Así que pensé que sería una buena idea utilizarCPcon su opción interactiva (cp-yo) para comprobar si el archivo de destino existe. Probé esto:

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

Esto escribe "Hola" en test.txt si test.txt aún no existe, pero cancela la copia si test.txt existe, ya que cp lee la respuesta sobre si se debe sobrescribir o no solo desde esa tubería.

Sin embargo, esto

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

funciona según lo previsto, cp parece tomar el desriptor de archivos del subproceso como fuente y esto se cp'ied a test.txt y simplemente no sé por qué.

¿Alguna idea, explicación o mejor forma de hacerlo?

Respuesta1

Utilice otro descriptor de archivo en lugar de/dev/stdin

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

O aún programable a través de sí(1)

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

En ambas variantes, los extras { ... }solo cp -i ...son necesarios en zsh, para evitar su carácter no estándar.multioscaracterística.

Esto debería funcionar en cualquier shell estándar y en cualquier sistema que admita /dev/fd/Narchivos, excepto en la combinación Linux + ksh93, que no funcionará porque ksh93 está implementando tuberías con sockets Unix, que en Linux no se pueden abrir /dev/fd/N(ni siquiera echo | cat /dev/stdinfuncionarán).

En realidad, dañarás echo -n "Hello" | cp -i /dev/stdin test.txtel archivo si, en lugar de "Hello"hacerlo, lo colocas "You suck!"allí. Ésa es una de las razones por las que no deberías confiar en cp -i.

Respuesta2

Shells como bashya pueden proteger contra la sobrescritura de archivos con una redirección

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

Si desea poder preguntarle al usuario antes de sobrescribir, usaría algo como esto en lugar de la noclobberconfiguración

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

información relacionada