Ist es ein UUOC (nutzloser Gebrauch von cat), um eine Datei zu einer anderen umzuleiten?

36

Wenn ich möchte, dass der Inhalt von file2mit dem Inhalt von übereinstimmt file1, könnte ich natürlich einfach laufen cp file1 file2.

Wenn ich jedoch beibehalten möchten alles über file2 außer dem Inhalt-Besitzer, Berechtigungen, erweiterte Attribute, ACLs, Hard - Links, etc., etc., dann würde ich nicht ausgeführt werden soll cp. * In diesem Fall möchte ich nur die plop Inhalt von file1in file2.

Es sieht so aus, als würde das folgendermaßen aussehen:

< file1 > file2

Aber es geht nicht. file2wird auf nichts abgeschnitten und nicht geschrieben. Jedoch,

cat < file1 > file2

funktioniert .

Es hat mich überrascht, dass die erste Version nicht funktioniert.

Ist die zweite Version ein UUOC? Gibt es eine Möglichkeit, dies zu tun, ohne einen Befehl aufzurufen, indem lediglich Umleitungen verwendet werden?

Anmerkung: Mir ist bewusst, dass UUOC eher ein pedantischer Punkt als ein echtes Anti-Pattern ist.

* Wie tniles09 entdeckt , cp Wille tatsächlich Arbeit in diesem Fall.

Platzhalter
quelle
3
Ob Sie das < file1 > file2tun, was Sie wollen, hängt von der Shell ab.
Michael Homer
13
Nun, es ist eine nutzlose Verwendung von <...
jwodder
2
Was ist ein Anti-Pattern ?
mikeserv
6
@jwodder - das stimmt nicht. vor allem, wenn es sich um eine Kopie handelt. Überlegen Sie, was passiert, wenn file1es keine gibt oder nicht lesbar ist, und öffnen Sie es mit, < bevor die > Ausgabe geöffnet wird. Überlegen Sie dann, was passiert, wenn Sie catversuchen, sie zu öffnen.
mikeserv
3
@JonathanLeffler In zsh wird cat(standardmäßig) ein leerer Befehl mit Umleitungen aufgerufen , der im Wesentlichen den zweiten Befehl ausführt . Siehe Stéphane Chazelas' Antwort unten für mehr dazu als fits in einem Kommentar.
Michael Homer

Antworten:

58

cat < file1 > file2ist kein UUOC. Klassisch <und >Umleitungen, die Duplikaten von Dateideskriptoren auf Systemebene entsprechen. Duplikationen von Dateideskriptoren alleine machen nichts ( >Umleitungen öffnen sich mit O_TRUNC, um genau zu sein, schneiden Umleitungen die Ausgabedatei ab). Lassen Sie sich nicht von den < >Symbolen verwirren. Umleitungen verschieben keine Daten - sie weisen Dateideskriptoren anderen Dateideskriptoren zu.

In diesem Fall öffnen Sie file1die Datei Descriptor Dateideskriptor und zuweisen 0( <file1== 0<file1) und file2und weisen diesen Dateideskriptor Dateideskriptor 1( >file2== 1>file2).

Nachdem Sie nun zwei Dateideskriptoren haben, müssen Sie einen Prozess zum Verschieben von Daten zwischen den beiden ausführen - und das ist der Grund catdafür.

PSkocik
quelle
11
Vielleicht bin es nur ich, aber mein Lieblingsteil dieser Antwort ist Ihre Verwendung des Wortes "Schaufel". :) Sehr klar, danke.
Wildcard
1
@Wildcard Ich hätte "pumpen" der "Schaufel" vorgezogen, aber immer noch ein gutes Wort. +1
Mehrdad
Warum ist Schaufel ein gutes Wort?
Bubakazouba
1
Man schaufelt einen Haufen Schmutz, eine Schaufel voll, von einem Haufen zum anderen, während die Daten pufferweise kopiert werden. Das ist eine gute Analogie.
bsd
1
In Ihrem ersten Satz sagen Sie, dass die Dateideskriptoren dupliziert werden. Werden sie dupliziert oder neu zugewiesen (wie aus Ihrem zweiten Absatz und dem Verhalten des Features hervorgeht)?
Greg Bell
17

Dies ist nicht der Fall, da das betreffende Verhalten, wie andere bereits ausgeführt haben, von der Shell abhängt. Wie Sie (die OP) betont haben, ist dies ein wenig umständlich , vielleicht sogar humorvoll? Art von Thema.

Doch auf GNU - Systemen Ihre erste Prämisse hat eine andere Lösung zur Verfügung: cp --no-preserve=all file1 file2. Probieren Sie dies aus, ich denke, es wird Ihrer beschriebenen Situation gerecht (z. B. Ändern von Inhalten, file2ohne die Attribute zu ändern).

Beispiel :

$ 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 Eigentlich bemerkte ich nur , dass mein System ist cpselbst scheint Attribute zu erhalten , es sei denn -aoder -pfestgelegt sind. Ich benutze Bash Shell und GNU Coreutils. Ich denke, Sie lernen jeden Tag etwas Neues ...


Testergebnisse (per Wildcard) inklusive Hardlink und unterschiedlichen Berechtigungen:

$ 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
quelle
Nett. Ich habe meinen eigenen Test mit einem festen Link und verschiedenen Berechtigungen durchgeführt, und es scheint, dass Sie richtig sind.
Wildcard
Fügte meine Testergebnisse hinzu; Ich hoffe es macht dir nichts aus. :) Ich habe keine ACLs oder erweiterten Attribute getestet, aber da die Inode-Nummer erhalten bleibt, bin ich mir zu 99% sicher, dass dies auch der Fall ist.
Wildcard
Schön, das macht mir nichts aus. :-)
tniles
13

In zshder Shell, in < file1 > file2der gearbeitet wird, wird die Shell aufgerufen cat.

Für eine Befehlszeile , die nur von Umleitungen und keinen Befehl noch Zuordnungen besteht zshInvokes $NULLCMD( catStandardeinstellung) , es sei denn die einzige Umleitung ist ein <, in dem Fall $READNULLCMD( pagervoreingestellt) wird stattdessen aufgerufen. (Es sei denn, es zshist in shoder cshEmulation. In diesem Fall verhält es sich wie die Shells, die es emuliert.)

So:

< file1 > file2

ist eigentlich das gleiche wie

cat < file1 > file2

und

< file1

ist das gleiche wie

pager < file1
Stéphane Chazelas
quelle
Für den Datensatz funktioniert diese Syntax nicht für ksh93
fpmurphy
8
< from > to

funktioniert nicht, weil dort kein Befehl vorhanden ist; kein prozess. Die Shell öffnet / erstellt die Dateien und ordnet die Umleitungen an (dh die Dateideskriptoren, die auf diese Dateien verweisen, werden als 0 und 1 gepflanzt: Standardeingabe und Standardausgabe). Es ist jedoch nichts zu tun, um eine Schleife zum Lesen von der Standardeingabe und zum Schreiben in die Standardausgabe auszuführen.

zshDies funktioniert, indem ein vom Benutzer konfigurierbarer Befehl in diesem "Null-Befehl" -Fall ersetzt wird. Der Befehl ist in der Befehlszeile nicht sichtbar, aber immer noch vorhanden. Hierfür wird ein Prozess erstellt, der auf die gleiche Weise funktioniert. NULLCMDist catvoreingestellt, bedeutet also < from > totatsächlich in , es sei denn, es ist auf etwas anderes gesetzt; Es ist ein "implizites Katzenkommando". cat < from > tozshNULLCMD

Eine "nutzlose Verwendung von cat" tritt auf, wenn catsie als Vermittler verwendet wird, um aus einer Datei zu lesen und die Daten einem anderen Prozess zuzuführen, dessen Dateideskriptor einfach mit der Originaldatei verbunden werden könnte.

Wenn cates aus der Situation entfernbar ist, so dass die verbleibenden Befehle immer noch dieselbe Aufgabe ausführen können, ist es nutzlos. Wenn es nicht entfernbar ist, ist es nicht nutzlos.

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

A , catdas ist ersetzbar ist nicht das Gleiche. Zum Beispiel cat > filekönnen wir stattdessen verwenden vi file, um die Datei zu erstellen. Dies gilt nicht als Entfernung von cat, während alles, was noch übrig ist, verwendet wird, um dieselbe Aufgabe zu erfüllen.

Wenn dies catder einzige Befehl in der Pipeline ist, kann er natürlich nicht entfernt werden. Keine Umlagerung dessen, was noch übrig ist, wird die entsprechende Arbeit leisten.

Einige Shell-Skripter verwenden catdiese Option, weil sie der Ansicht sind, dass sie den Eingabeoperanden näher an die linke Seite der Befehlszeile verschieben können. Umleitungen können sich jedoch an einer beliebigen Stelle in der Befehlszeile befinden:

# If you're so inclined:
# move source archive operand to the left without cat:
$ < archive.tar tar xf - > listing
Kaz
quelle
Übrigens müssen Sie nicht f -für Teer verwenden. tar xf -ist einfach tar x.
dnt
@mikeserv Wo steht, dass catan der Dateierstellung beteiligt ist? Die Antwort sagt eindeutig, dass die Shell dies tut. Auf welches Problem > filebeziehen Sie sich? Ich verwende es oft alleine, um eine vorhandene Datei auf Null zu kürzen oder sicherzustellen, dass eine solche vorhanden ist. Bei dieser Frage geht es darum, warum < from > tonicht funktioniert cat < from > tound UUoC, nicht "Bitte geben Sie mir Gründe, warum catkein guter Ersatz für cp".
Kaz
1
@dnt, tarist der Bandarchivierer . Viele tarImplementierungen funktionieren standardmäßig immer noch mit dem ersten Bandgerät.
Stéphane Chazelas
1

< file1 > file2 Scheint shellabhängig zu sein, auf zsh funktioniert es, auf bash nicht.

edit: falsche aussage gelöscht

Tastytea
quelle
cp -aErhält die Attribute von Datei1 und überschreibt die Attribute von Datei2. Gegenteil von gewünschtem Verhalten. Plus Ich kann nicht einmal sagen , durch den Mann an Seite schauen , was mit harten Links passieren wird, aber ich denke , es ist sicher zu sagen , dass file2 ist schwer Links werden nicht erhalten bleiben.
Wildcard
Du hast recht, ich habe die Frage nicht sorgfältig genug gelesen.
tastytea
1

Zusätzlich zu all den guten Antworten können Sie eine UUOC von vermeiden Simulation ein 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.

Diese Befehle kopieren die Metadaten der Datei nicht wie üblich cp.

Jens
quelle
Stimmt, aber es ist erwähnenswert, dass sie keinen Vorteil und nur Nachteile (Leistung, Zuverlässigkeit) gegenüber haben cat. Hier benötigen Sie einen Befehl, um Daten zwischen den beiden Dateideskriptoren zu verschieben. Dies catist einer der besten. Sehen Sie auch, pvwelche unter splice()Linux für Fifos verwendet werden können (obwohl es nicht fadvise(POSIX_FADV_SEQUENTIAL)wie GNU catfunktioniert).
Stéphane Chazelas
Der ddBefehl für Binärdateien scheint gut zu sein ... oder würde cater für Binärdateien genauso gut funktionieren?
Wildcard
@Wildcard catfunktioniert auch für Binärdateien (Unix unterscheidet im Allgemeinen nicht; einige Tools arbeiten jedoch zeilenweise, wie awk, grep, wc, ... POSIX definiert theoretisch auch eine minimale größte Zeilenlänge Ein zeilenorientiertes Tool kann sich weigern, übermäßig große Zeilen zu verarbeiten.)
Jens
2
@ StéphaneChazelas Diese Antwort war auch als Augenzwinkernd gedacht. Trotz der Jahreszeit scheinen einige Leute allergisch auf Spaß zu reagieren (nicht gegen Sie gerichtet; ich schätze Ihre Shell-Expertise und Opengroup-Standardarbeit).
Jens
sed '' < file1 > file2;-)
Digitales Trauma
0

Wenn es funktioniert, beheben Sie es nicht.

ich würde ... benutzen

cat < file1 > file2

und nicht den PC von der Semantik schwitzen.

krazykyngekorny
quelle