Wie vermeide ich eine nutzlose Verwendung von cat beim Parsen einer Datei?

8

Ich habe eine Datei mit einer Liste von Verzeichnissen. Zum Beispiel

/foo/bar/dir1
/foo/bar/dir2
/foo/bar/dir3

Ich möchte alle diese Verzeichnisse erstellen. Folgendes habe ich getan:

for dir in $(cat myfile); do mkdir $dir; done

Was wäre der richtige Weg, um den "nutzlosen Gebrauch von Katze" zu vermeiden?

Im Idealfall konzentrieren sich die Antworten auf Ksh88, aber ich interessiere mich auch für andere Shells

Rahmu
quelle
2
Wenn sich alle Verzeichnisse in einem einzigen Verzeichnis befinden und nur wenige vorhanden sind, verwenden Sie die Klammererweiterung der Shell. $ mkdir /foo/bar/dir{1,2,3}oder$ mkdir /foo/bar/{dir1,dir2,dir3}
Nikhil Mulley
mögliches Duplikat von Wie kann ich Zeile für Zeile aus einer Variablen in Bash lesen?
Gilles 'SO - hör auf böse zu sein'
Vielen Dank an Gilles für den Hinweis auf diese Frage, ich war mir dessen nicht bewusst. Für die Aufzeichnung wollte ich aus einer Datei lesen, die keine Variable ist. Und meine Frage ist Shell-Agnostiker (wenn überhaupt, was ich erwähne ksh). Auf jeden Fall fand ich meine Antwort; Ich war nicht vertraut mit read. Die Manpage erledigt den Rest.
Rahmu

Antworten:

13

Der Vorschlag von AProgrammer zur Verwendung xargsist häufig am besten. Eine andere Option ist die Verwendung der Umleitung in eine whileSchleife, mit der zusätzliche Befehle und Variablen festgelegt werden können:

while read -r dir; do mkdir $dir; done < myfile

Ein Beispiel für eine kompliziertere Struktur wäre:

now=`date +%Y%m%d.%H%M%S`
while read -r dir; do
    newdistfile="/tmp/dist-`echo $dir | tr / _`.tgz"
    mv $dir ~/backups/$dir.$now &&
        mkdir $dir &&
        tar xzfC $newdistfile $dir
done < myfile

Dies ist nicht möglich, xargsohne ein "Hilfsprogramm" zu schreiben.

Arcege
quelle
Was sind die Grenzen der Verwendung von xargsover read? Nach meinem Verständnis xargswird dies einen neuen Prozess readauslösen (im Gegensatz zu einer eingebauten Shell). Wollen Sie das nicht vermeiden?
Rahmu
xargsauf einem einzigen Befehl betrieben werden, wenn Sie also (wie mehr als ein, eine eine Verbindung Erklärung haben wollen if, whileoder for, etc.) oder eine variable Einstellung, dann können Sie nicht verwenden xargs. Ja, xargs gibt eine neue Anweisung und eine für eine bestimmte Anzahl von Eingabezeilen frei, was sehr wenig Aufwand bedeutet. Einige ältere Versionen von verwenden xargsjedoch keine -0Option. Daher ist a der while readrichtige Weg, wenn die Namen der Eingabeverzeichnisse Leerzeichen enthalten.
Arcege
11

Ich würde so etwas tun

xargs mkdir < myfile
Ein Programmierer
quelle
1
Warum "-n 1"? Sie können mehrere Verzeichnisse mit einem Aufruf von mkdir erstellen.
Ddeimeke
1
@ddeimeke, weil ich mich nicht daran erinnerte, ob es POSIX oder nur eine gemeinsame Erweiterung ist. Jetzt habe ich überprüft und es ist in SUSv2.
AProgrammer
3
Nutzlose Verwendung von Xargs. ;)
Benutzer unbekannt
11

Zumindest in Bash, solange es keine Dateinamen gibt, die Leerzeichen und Zeilenumbrüche enthalten, gilt Folgendes:

mkdir $(< myfile) 

funktioniert. Also haben wir einen nutzlosen Einsatz haben for, xargsauch.

<startet im Gegensatz zu Bash keinen neuen Prozess cat, aber ich weiß es nicht ksh.

Benutzer unbekannt
quelle
2
+1 zur Klärung des Leerzeichenproblems im Gegensatz zu anderen Antworten.
Enzotib
4

Dies ist die Lösung, die näher an Ihrem ursprünglichen Skript liegt und die nutzlose Katze vermeidet

for dir in $(<myfile); do mkdir $dir; done

Es enthält jedoch immer noch eine nutzlose Schleife.

jlliagre
quelle
2

Ich würde nicht sagen, dass das eine nutzlose Verwendung von Katze ist.

Im klassischen Sinne bedeutet ein UUOC Schreiben:

cat file | some_command and its args ...

statt gleichwertig und billiger

<file some_command and its args ...

oder (äquivalent und klassischer)

some_command and its args ... < file

In diesem Fall:

for dir in $(cat myfile); do mkdir $dir; done

Es gibt keinen Befehl, in den die Ausgabe von geleitet catwird.

Es gibt sicherlich Alternativen, die nicht verwendet werden cat. Insbesondere für bash und ksh $(<myfile)ist es wahrscheinlich schneller als $(cat myfile), obwohl nicht alle Shells dieses Konstrukt unterstützen. Aber ich würde den ursprünglichen Code nicht mehr als "nutzlose Verwendung von Katze" bezeichnen, als ich die Lösung von AProgrammer als "nutzlose Verwendung von Xargs" bezeichnen würde.

Keith Thompson
quelle
1

Mit bash4 und begrenzt durchARG_MAX

mapfile -t <file && mkdir -- "${MAPFILE[@]}"
iruvar
quelle
oder zmodload zsh/mapfile && mkdir -- ${(f)mapfile[infile]}wenn die Shell istzsh
don_crissti