È un UUOC (uso inutile di cat) per reindirizzare un file a un altro?


36

Se voglio fare in modo che i contenuti di file2abbinino i contenuti di file1, potrei ovviamente semplicemente eseguire cp file1 file2.

Tuttavia, se voglio conservare tutto su file2 tranne il contenuto-proprietario, i permessi, attributi estesi, ACL, hard link, ecc, ecc, quindi non vorrei correre cp. * In questo caso voglio solo plop il contenuto di file1into file2.

Sembra che il seguente lo farebbe:

< file1 > file2

Ma non funziona file2viene troncato a nulla e non scritto. Tuttavia,

cat < file1 > file2

fa il lavoro.

Mi ha sorpreso che la prima versione non funzioni.

La seconda versione è un UUOC? C'è un modo per farlo senza invocare un comando, semplicemente usando i reindirizzamenti?

Nota: sono consapevole che UUOC è più un punto pedante che un vero anti-pattern.

* Come tniles09 scoperto , cp volontà nel lavoro fatto in questo caso.


3
Se < file1 > file2fa quello che vuoi dipende dalla shell.
Michael Homer,

13
Bene, è un uso inutile di <...
jwodder,

2
cos'è un anti-pattern ?
Mikeserv,

6
@jwodder - non è vero. soprattutto quando parli di una copia. considera cosa succede quando file1non esiste oppure è illeggibile e lo apri < prima > dell'apertura dell'output, quindi considera cosa succede quando permetti catdi provare ad aprirlo.
Mikeserv,

3
@JonathanLeffler In zsh un comando vuoto con reindirizzamenti richiama cat(per impostazione predefinita), essenzialmente eseguendo il secondo comando. Vedi la risposta di Stéphane Chazelas di seguito per ulteriori informazioni rispetto a quelle contenute in un commento.
Michael Homer,

Risposte:


58

cat < file1 > file2non è un UUOC. Classicamente <ed >esegui reindirizzamenti che corrispondono alle duplicazioni dei descrittori di file a livello di sistema. Le duplicazioni dei descrittori di file da sole non fanno nulla (bene, i >reindirizzamenti si aprono con O_TRUNC, quindi, per essere precisi, i reindirizzamenti di output troncano il file di output). Non lasciare che i < >simboli ti confondano. I reindirizzamenti non spostano i dati, ma assegnano i descrittori di file ad altri descrittori di file.

In questo caso, apri file1e assegni quel descrittore di file al descrittore di file 0( <file1== 0<file1) file2e assegni quel descrittore di file al descrittore di file 1( >file2== 1>file2).

Ora che hai due descrittori di file, hai bisogno di un processo per spalare i dati tra i due — ed è quello che catserve.


11
Forse sono solo io, ma la mia parte preferita di questa risposta è il tuo uso della parola "pala". :) Molto chiaro, grazie.
Wildcard il

1
@Wildcard Avrei preferito "pompa" piuttosto che "pala", ma comunque una buona parola. +1
Mehrdad,

perché la pala è una buona parola?
bubakazouba,

1
Uno spala una pila di terra, una pala alla volta, da una pila all'altra mentre i dati vengono copiati buffer per buffer. È una buona analogia.
bsd

1
Nella tua prima frase, dici che i descrittori di file vengono duplicati. Vengono duplicati o riassegnati (come sembra indicare il secondo paragrafo e il comportamento della funzionalità)?
Greg Bell,

17

Non è perché, come altri hanno sottolineato, il comportamento in questione dipende dalla shell. Come hai sottolineato (l'OP), questo è un po ' pedante , forse anche divertente? , una specie di argomento.

Tuttavia, nei sistemi GNU, la tua premessa iniziale ha un'altra soluzione disponibile: cp --no-preserve=all file1 file2. Prova questo, penso che soddisferà la tua situazione descritta (ad esempio modificando i contenuti file2senza modificarne gli attributi).

Esempio :

$ 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!

UPDATE In realtà, ho appena notato che il mio sistema cpdi per sé sembra conservare gli attributi a meno che -ao -psono specificati. Sto usando bash shell e coreutils GNU. Immagino che impari qualcosa di nuovo ogni giorno ...


Risultati dei test (tramite carattere jolly) inclusi hard link e autorizzazioni diverse:

$ 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
$ 

Bello. Ho eseguito il mio test includendo un collegamento reale e autorizzazioni diverse e sembra che tu abbia ragione.
Wildcard il

Aggiunti i risultati dei miei test; spero non ti dispiaccia. :) Non ho testato ACL o attributi estesi, ma dato che il numero di inode è preservato, sono sicuro al 99% anche quelli.
Wildcard il

Bello ... non importa affatto. :-)
tniles il

13

In zsh, la shell dove < file1 > file2funziona, la shell invoca cat.

Per una riga di comando che consiste solo di reindirizzamenti e nessun comando né assegnazione, zshinvoca $NULLCMD( catper impostazione predefinita) a meno che l'unico reindirizzamento sia <uno nel qual caso viene invece richiamato $READNULLCMD( pagerper impostazione predefinita). (a meno che non zshsia presente sho cshemulato nel qual caso si comporta come le shell che emula).

Così:

< file1 > file2

è in realtà lo stesso di

cat < file1 > file2

e

< file1

equivale a

pager < file1

Per la cronaca, questa sintassi non funziona per ksh93
fpmurphy il

8
< from > to

non funziona perché non vi è alcun comando lì; nessun processo. La shell apre / crea i file e organizza i reindirizzamenti (il che significa che i descrittori di file che fanno riferimento a questi file sono impiantati come 0 e 1: input standard e output standard). Ma non c'è nulla da fare per eseguire un loop per leggere dallo standard input e scrivere nello standard output.

zshfa funzionare questo sostituendo un comando configurabile dall'utente in questo caso "comando nullo". Il comando non è visibile nella riga di comando, ma è ancora lì. Viene creato un processo per esso e funziona allo stesso modo. NULLCMDè catdi default, quindi < from > toin realtà significa cat < from > to in zsh, a meno che non NULLCMDsia impostato su qualcosa d'altro; è un comando "gatto implicito".

Un "uso inutile di cat" si verifica quando catviene utilizzato come intermediario per leggere da un file e alimentare i dati a un altro processo, il cui descrittore di file potrebbe essere semplicemente collegato al file originale.

Se catè rimovibile dalla situazione, in modo che i comandi rimanenti possano ancora eseguire la stessa attività, è inutile. Se non è rimovibile, non è inutile.

# 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)

Una catche è sostituibile non è la stessa cosa. Ad esempio invece cat > fileche possiamo usare vi fileper creare il file. Ciò non vale come rimozione di cat, mentre si utilizza tutto ciò che è rimasto per raggiungere lo stesso compito.

Se catè l' unico comando nella pipeline, ovviamente non può essere rimosso; nessuna riorganizzazione di ciò che resta farà il lavoro equivalente.

Alcuni programmatori di shell usano catperché pensano che li consenta di spostare l'operando di input più vicino al lato sinistro della riga di comando. Tuttavia, i reindirizzamenti possono essere ovunque nella riga di comando:

# If you're so inclined:
# move source archive operand to the left without cat:
$ < archive.tar tar xf - > listing

a proposito, non è necessario utilizzare f -per tar. tar xf -è giusto tar x.
dnt

@mikeserv Dove dice che catè coinvolto nella creazione del file? La risposta dice chiaramente che la shell fa questo. A quale problema > fileti riferisci? Lo uso spesso da solo per troncare un file esistente a lunghezza zero o per garantire che esista. Questa domanda riguarda il motivo per cui < from > tonon funziona cat < from > to, e UUoC, non "per favore, spiegami perché catnon è un buon sostituto cp".
Kaz,

1
@dnt, tarè l' archiviatore su nastro . Molte tarimplementazioni funzionano ancora con il primo dispositivo a nastro per impostazione predefinita.
Stéphane Chazelas,

1

< file1 > file2 Sembra essere dipendente dalla shell, su zsh funziona, su bash no.

modifica: dichiarazione falsa cancellata


cp -aconserva gli attributi di file1 e sovrascrive gli attributi di file2. Di fronte al comportamento desiderato. Inoltre non posso dire nemmeno guardando la pagina man che cosa accadrà con i collegamenti reali, ma penso che sia sicuro dire che i collegamenti fisici di file2 non verranno conservati.
Wildcard il

Hai ragione, non ho letto la domanda abbastanza attentamente.
tastytea,

1

Oltre a tutte le risposte valide, puoi evitare 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.

Questi comandi non copiano i metadati del file, come cpfarebbe un semplice .


È vero, ma vale la pena ricordare che non hanno vantaggi e svantaggi (prestazioni, affidabilità) cat. Qui è necessario un comando per inserire i dati tra i due descrittori di file ed catè uno dei migliori per questo. Vedi anche pvquale sarebbe in grado di usare splice()su Linux per FIFOS (anche se non funziona fadvise(POSIX_FADV_SEQUENTIAL)come GNU cat).
Stéphane Chazelas,

Il ddcomando per i file binari sembra buono ... o catfunzionerebbe altrettanto bene per i file binari?
Wildcard il

@Wildcard catfunziona anche per i file binari (Unix generalmente non fa distinzioni; tuttavia, alcuni strumenti funzionano specificamente riga per riga, come awk, grep, wc, ... POSIX definisce anche una lunghezza minima della linea maggiore, quindi in teoria uno strumento orientato alle linee potrebbe rifiutare di gestire linee eccessivamente grandi.)
Jens,

2
@ StéphaneChazelas Anche questa risposta è stata intesa come ironica. Sembra che, nonostante la stagione, alcune persone siano allergiche al divertimento (non indirizzate a te; apprezzo la tua competenza nella shell e il lavoro degli standard Opengroup).
Jens,

sed '' < file1 > file2;-)
Digital Trauma,

0

Se funziona, non ripararlo.

io userei

cat < file1 > file2

e non sudare il PC della semantica.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.