¿Es un UUOC (uso inútil de cat) para redirigir un archivo a otro?

36

Si quiero hacer que el contenido file2coincida con el contenido de file1, obviamente podría simplemente ejecutarlo cp file1 file2.

Sin embargo, si quiero conservar todo alrededor file2 , excepto el contenido-propietario, permisos, atributos extendidos, ACL, enlaces duros, etc., etc., entonces yo no desee ejecutar cp. * En ese caso, sólo quiero el plop contenido de file1into file2.

Parece que lo siguiente lo haría:

< file1 > file2

Pero no funciona. file2se trunca a nada y no se escribe en. Sin embargo,

cat < file1 > file2

hace el trabajo.

Me sorprendió que la primera versión no funcione.

¿Es la segunda versión un UUOC? ¿Hay alguna manera de hacer esto sin invocar un comando, simplemente usando redirecciones?

Nota: Soy consciente de que UUOC es más un punto pedante que un verdadero antipatrón.

* Como tniles09 descubrió , cp voluntad en el trabajo hecho en este caso.

Comodín
fuente
3
Si < file1 > file2hace lo que quiere depende de la shell.
Michael Homer
13
Bueno, es un uso inútil de <...
jwodder
2
¿Qué es un antipatrón ?
mikeserv
66
@jwodder: eso no es cierto. especialmente cuando estás hablando de una copia. considere lo que sucede cuando file1no existe o si no es legible y lo abre < antes de > que se abra la salida, y luego considere lo que sucede cuando permite catintentar abrirlo.
mikeserv
3
@JonathanLeffler En zsh, un comando vacío con invocaciones de redireccionamiento cat(por defecto), esencialmente ejecuta el segundo comando. Vea la respuesta de Stéphane Chazelas a continuación para obtener más información sobre eso que lo que cabe en un comentario.
Michael Homer

Respuestas:

58

cat < file1 > file2No es un UUOC. Clásicamente, <y >realice redirecciones que correspondan a duplicaciones de descriptores de archivo a nivel del sistema. Las duplicaciones del descriptor de archivo por sí mismas no hacen nada (bueno, las >redirecciones se abren con O_TRUNC, por lo que, para ser precisos, las redirecciones de salida truncan el archivo de salida). No dejes que los < >símbolos te confundan. Las redirecciones no mueven datos: asignan descriptores de archivo a otros descriptores de archivo.

En este caso, abre file1y asigna ese descriptor de archivo al descriptor de archivo 0( <file1== 0<file1) file2y asigna ese descriptor de archivo al descriptor de archivo 1( >file2== 1>file2).

Ahora que tiene dos descriptores de archivo, necesita un proceso para intercambiar datos entre los dos, y para eso catestá.

PSkocik
fuente
11
Tal vez solo soy yo, pero mi parte favorita de esta respuesta es su uso de la palabra "pala". :) Muy claro, gracias.
Comodín
1
@Wildcard Hubiera preferido "bomba" sobre "pala", pero aún así es una buena palabra. +1
Mehrdad
¿Por qué es pala una buena palabra?
bubakazouba
1
Una pala llena un montón de tierra, una pala llena a la vez, de una pila a otra a medida que los datos se copian búfer por búfer. Es una buena analogía.
bsd
1
En su primera oración, dice que los descriptores de archivo se están duplicando. ¿Están siendo duplicados o reasignados (como parece indicar su segundo párrafo y el comportamiento de la función)?
Greg Bell
17

No lo es, porque como otros han señalado, el comportamiento en cuestión depende de la concha. Como usted (el OP) ha señalado, esto es un poco pedante , ¿tal vez incluso humorístico? , tipo de tema.

Sin embargo, en los sistemas GNU, su premisa inicial tiene otra solución disponible: cp --no-preserve=all file1 file2. Pruebe esto, creo que satisfará su situación descrita (por ejemplo, modificando contenidos file2sin modificar sus atributos).

Ejemplo :

$ ls -l
    total 8
    -rw-r--r-- 1 tniles sambashare 16 Dec 16 12:21 fezzik
    -rw-r--r-- 1 tniles tniles     14 Dec 16 12:16 fred
$ cat *
    Lookout, world!
    Hello, world!
$ cp --no-preserve=all fred fezzik 
$ ls -l
    total 8
    -rw-r--r-- 1 tniles sambashare 14 Dec 16 12:22 fezzik
    -rw-r--r-- 1 tniles tniles     14 Dec 16 12:16 fred
$ cat *
    Hello, world!
    Hello, world!

ACTUALIZACIÓN En realidad, sólo se dio cuenta de que mi sistema cppor sí mismo parece conservar atributos a menos -ao -pestán especificados. Estoy usando bash shell y GNU coreutils. Supongo que aprendes algo nuevo todos los días ...


Resultados de la prueba (por comodín) incluyendo enlace duro y diferentes permisos:

$ ls -li
total 12
913966 -rw-rw-r-- 1 vagrant vagrant 30 Dec 16 20:26 file1
913965 -rwxrw---- 2 pete    vagrant 39 Dec 16 20:35 file2
913965 -rwxrw---- 2 pete    vagrant 39 Dec 16 20:35 hardlinktofile2
$ cat file1
This is the contents of file1
$ cat file2
This is the original contents of file2
$ cp file1 file2
$ ls -li
total 12
913966 -rw-rw-r-- 1 vagrant vagrant 30 Dec 16 20:26 file1
913965 -rwxrw---- 2 pete    vagrant 30 Dec 16 20:37 file2
913965 -rwxrw---- 2 pete    vagrant 30 Dec 16 20:37 hardlinktofile2
$ cat file1
This is the contents of file1
$ cat file2
This is the contents of file1
$ 
tniles
fuente
Agradable. Ejecuté mi propia prueba, incluido un enlace duro y diferentes permisos, y parece que estás en lo correcto.
Comodín
Agregué los resultados de mi prueba; Espero que no te importe. :) No probé ACL o atributos extendidos, pero dado que se conserva el número de inodo , estoy 99% seguro de que también lo serían.
Comodín
Bien ... no me importa en absoluto. :-)
tniles
13

En zshel shell donde < file1 > file2funciona, el shell invoca cat.

Para una línea de comando que consiste solo en redirecciones y sin comando ni asignaciones, zshinvoca $NULLCMD( catpor defecto) a menos que la única redirección sea una <en cuyo caso $READNULLCMD( pagerpor defecto) se invoca en su lugar. (eso es a menos que zshesté en sho cshemulación en cuyo caso se comporta como los shells que emula).

Asi que:

< file1 > file2

en realidad es lo mismo que

cat < file1 > file2

y

< file1

es lo mismo que

pager < file1
Stéphane Chazelas
fuente
Para el registro, esta sintaxis no funciona para ksh93
fpmurphy
8
< from > to

no funciona porque no hay comando allí; sin proceso El shell abre / crea los archivos y organiza las redirecciones (lo que significa que los descriptores de archivo que hacen referencia a estos archivos se plantan como 0 y 1: entrada estándar y salida estándar). Pero no hay nada que hacer, ejecutar un ciclo para leer desde la entrada estándar y escribir en la salida estándar.

zshhace que esto funcione al sustituir un comando configurable por el usuario en este caso de "comando nulo". El comando no está visible en la línea de comando, pero todavía está allí. Se crea un proceso para él y funciona de la misma manera. NULLCMDes catpor defecto, por lo que en < from > torealidad significa cat < from > to adentro zsh, a menos que NULLCMDesté configurado en otra cosa; es un comando "gato implícito".

Un "uso inútil de cat" ocurre cuando catse usa como intermediario para leer de un archivo y alimentar los datos a otro proceso, cuyo descriptor de archivo podría estar conectado al archivo original.

Si catse puede eliminar de la situación, de modo que los comandos restantes aún pueden realizar la misma tarea, no sirve de nada. Si no es extraíble, entonces no es inútil.

# useless, removable:
$ cat archive.tar | tar tf -    #  -->  tar tf archive.tar

# not removable (in POSIX shell):
$ cat > file
abc
[Ctrl-D]

# likewise:
STRING=$(cat file)

Un catque es reemplazable no es lo mismo. Por ejemplo, en lugar de cat > filepodemos usar vi filepara crear el archivo. Eso no cuenta como eliminación de cat, mientras se usa lo que queda para lograr la misma tarea.

Si cates el único comando en la tubería, entonces, por supuesto, no se puede eliminar; ninguna reorganización de lo que quede hará el trabajo equivalente.

Algunos scripters de shell usan catporque piensan que les permite mover el operando de entrada más cerca del lado izquierdo de la línea de comando. Sin embargo, las redirecciones pueden estar en cualquier lugar de la línea de comando:

# If you're so inclined:
# move source archive operand to the left without cat:
$ < archive.tar tar xf - > listing
Kaz
fuente
por cierto, no tienes que usar f -para alquitrán. tar xf -es justo tar x.
dnt
@mikeserv ¿Dónde dice que catestá involucrado en la creación del archivo? La respuesta dice claramente que el shell hace esto. ¿A qué problema > filete refieres? A menudo lo uso solo para truncar un archivo existente a longitud cero o asegurar que exista. Esta pregunta es sobre por qué < from > tono funciona así cat < from > to, y UUoC, no "por favor, dame razones por las catque no es un buen sustituto de cp".
Kaz
1
@dnt, tares el archivador de cinta . Muchas tarimplementaciones aún funcionan con el primer dispositivo de cinta por defecto.
Stéphane Chazelas
1

< file1 > file2 Parece ser dependiente de shell, en zsh funciona, en bash no.

editar: declaración falsa eliminada

sabroso
fuente
cp -aconserva los atributos del archivo1 y sobrescribe los atributos del archivo2. Frente al comportamiento deseado. Además no puedo decir incluso mirando a la página del manual de lo que sucederá con los enlaces duros, pero creo que es seguro decir que fichero2 se 's enlaces duros no ser preservados.
Comodín
Tienes razón, no leí la pregunta con suficiente cuidado.
tastytea
1

Además de todas las buenas respuestas, puede evitar un UUOC simulando un cat:

awk 1 file1 > file2   # For line-oriented text, not binaries.
dd if=file1 of=file2  # Works for binary files, too.
# many more geeky ways.

Estos comandos no copian los metadatos del archivo, como lo cpharía sin formato .

Jens
fuente
Es cierto, pero vale la pena mencionar que no tienen ventaja y solo tienen inconvenientes (rendimiento, confiabilidad) cat. Aquí necesita un comando para insertar datos entre los dos descriptores de archivo y cates uno de los mejores para eso. Vea también pvcuál podría usar splice()en Linux durante quince años (aunque no funciona fadvise(POSIX_FADV_SEQUENTIAL)como lo cathace GNU ).
Stéphane Chazelas
El ddcomando para archivos binarios parece bueno ... ¿o catfuncionaría igual de bien para archivos binarios?
Comodín el
@Wildcard cattambién funciona para archivos binarios (Unix generalmente no distingue; sin embargo, algunas herramientas funcionan específicamente línea por línea, como awk, grep, wc, ... POSIX también define una longitud mínima de línea más grande, por lo que en teoría una herramienta orientada a líneas podría negarse a tratar con líneas excesivamente grandes.)
Jens
2
@ StéphaneChazelas Esta respuesta también pretendía ser irónica. Parece que, a pesar de la temporada, algunas personas son alérgicas a la diversión (no están dirigidas a usted; valoro su experiencia en shell y el trabajo de los estándares de Opengroup).
Jens
sed '' < file1 > file2;-)
Digital Trauma
0

Si funciona, no lo arregles.

yo usaría

cat < file1 > file2

y no sudar la PC de la semántica.

krazykyngekorny
fuente