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/N
archivos, 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/stdin
funcionarán).
En realidad, dañarás echo -n "Hello" | cp -i /dev/stdin test.txt
el 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 bash
ya 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 noclobber
configuració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