Entfernen Sie den Pfad aus der Ausgabe des Befehls find


29

Ich habe ein Bash-Skript zum Bereitstellen von Code aus einer Beta-Umgebung in einer Produktionsumgebung, aber derzeit muss ich die Liste der Dateien einer TXT-Datei manuell hinzufügen, und manchmal vermisse ich einige. Grundsätzlich kopiert mein Bereitstellungsskript cat / loops die Dateien über. (exporte / importe db auch aber das ist nicht relevant..lol)

Wie auch immer, ich möchte den findBefehl verwenden, um eine Liste der Dateien zu erstellen, die in den letzten 14 Tagen geändert wurden. Das Problem ist, dass ich den Pfad entfernen ./muss, damit das Bereitstellungsskript funktioniert.

Hier ist ein Beispiel für die Verwendung des Befehls find:

finden . -Typ f -mtime -14> deploy.txt

Hier ist die Zeile, die deploy.txtin meinem Bereitstellungsskript vorkommt:

for i in `cat deploy.txt`; do cp -i /home/user/beta/public_html/$i /home/user/public_html/$i; done

Haben Sie eine Idee, wie Sie dies mithilfe von Bash-Skripten erreichen können?

Vielen Dank!


3
Gibt es einen Grund, warum Sie dafür nicht einfach rsync verwenden können? Es hört sich so an, als ob Sie versuchen, das Rad neu zu erfinden und es zu einem Dreieck zu machen.
ThatGraemeGuy

Ein gültiger Punkt, aber vor der Bereitstellung wird die deploy.txt überprüft und alles, was repariert werden muss, wird entfernt
Mikey1980

1
Führen Sie rsync möglicherweise im --dry-runModus aus und geben Sie das zur Überprüfung in eine Datei aus?
Zoredache

Antworten:


36

Sie können die -printfBefehlszeilenoption mit verwenden %f, um nur den Dateinamen ohne Verzeichnisinformationen zu drucken

find . -type f -mtime -14 -printf '%f\n' > deploy.txt

oder Sie können sed verwenden, um nur die ./ zu entfernen

find . -type f -mtime -14 | sed 's|^./||' >deploy.txt

Ich glaube, du musst dem entkommen /..
EEAA

5
Nicht, wenn Sie |als Trennzeichen verwenden.
User9517 unterstützt GoFundMonica

3
Mit %fwerden alle Verzeichnisse entfernt, nicht nur ./. Dadurch wird sein Bereitstellungsskript unterbrochen, wenn sich eine der von zurückgegebenen Dateien findin Unterverzeichnissen befindet.
James Sneeringer

2
@Iain Du musst dem allerdings entkommen .. Und vielleicht am besten einen Startanker verwenden:s|^\./||
James O'Gorman

12
Verwenden Sie %Panstelle von %f. Dadurch wird nur der in der Befehlszeile angegebene Pfad abgeschnitten.
TrueY

11

Das ./sollte harmlos sein. Die meisten Programme behandeln /foo/barund /foo/./barals gleichwertig. Mir ist klar, dass es nicht sehr schön aussieht, aber basierend auf dem, was Sie gepostet haben, sehe ich keinen Grund, warum es dazu führen würde, dass Ihr Skript fehlschlägt.

Wenn Sie es wirklich ausziehen möchten, sedist dies wahrscheinlich der sauberste Weg:

find . -type d -mtime 14 | sed -e 's,^\./,,' > deploy.txt

Wenn Sie sich auf einem System mit GNU find befinden (z. B. auf den meisten Linux-Systemen), können Sie dies auf einmal tun find -printf:

find . -type d -mtime 14 -printf "%P\n" > deploy.txt

Das %Pgibt den vollständigen Pfad jeder gefundenen Datei abzüglich des in der Befehlszeile angegebenen Pfads bis einschließlich des ersten Schrägstrichs zurück. Dadurch bleiben alle Unterverzeichnisse in Ihrer Verzeichnisstruktur erhalten.


1
Das ./Präfix ist eigentlich ein Merkmal; Andernfalls funktioniert die Weiterleitung der Ausgabe an andere Befehle nicht ordnungsgemäß, z. B. für Dateinamen, die mit einem Bindestrich beginnen.
Tripleee

1
@tripleee - Ich verstehe den Nutzen davon, aber OP fragte speziell, wie man es entfernt, weil es Probleme für sein Bereitstellungsskript verursachte. Sicher, es gibt vielleicht bessere Möglichkeiten, um das zu tun, was er tun muss, aber das ist ein Kaninchenbau, der weit über den Rahmen dessen hinausgeht, was gefragt wurde.
James Sneeringer

7

Warum musst du das ausziehen ./? Es ist gültig, in einem Pfad zu haben. So

cp -i dir1/./somefile dir2/./somefile

ist einfach ok!

Aber wenn Sie den Verzeichnisnamen in find %Pentfernen möchten, können Sie das Argument to verwenden -printf.

man find (1) sagt:

         %P     File's name with the name of the  command  line  argument
                 under which it was found removed.

Ein Beispiel

$ find other -maxdepth 1
other
other/CVS
other/bin
other/lib
other/doc
other/gdbinit
$ find other -maxdepth 1 -printf "%P\n"

CVS
bin
lib
doc
gdbinit

Achte auf die erste leere Zeile! Wenn Sie es vermeiden möchten, verwenden Sie-mindepth 1

$ find other -mindepth 1 -maxdepth 1 -printf "%P\n"
CVS
bin
lib
doc
gdbinit

3

Nun, Sie haben ein paar Möglichkeiten. Sie können die -printfOption in find verwenden, um nur den Dateinamen auszudrucken, oder Sie können ein Tool wie sed verwenden, um den Dateinamen einfach zu entfernen ./.

# simply print out the filename, will break if you have sub-directories.
find . -mtime -14 -printf '%f\n'

# strip a leading ./
find .  -mtime -14 | sed -e 's/^\.\///'

Können Sie mir ein Beispiel für die Verwendung geben? Sorry, Linux ist nicht wirklich mein Glück
Mikey1980

2
Schauen Sie noch einmal, es gibt Beispiele.
Zoredache

Einverstanden - versuchen Sie es einfach, Sie werden nichts mit einer Kombination aus find und sed anstellen.
EEAA

3

"find -printf" funktioniert unter FreeBSD nicht, weil find keine solche Option hat. In diesem Fall kann AWK helfen. Es gibt einen Nachnamen ($ NF) zurück, sodass es in jeder Tiefe funktionieren kann.

find /usr/local/etc/rc.d -type f | awk -F/ '{print $NF}'

PS: Entnommen aus D.Tansleys "Linux and Unix Shell Programming" Buch


2

Eine schnelle Lösung cutfür die Ausgabe des findBefehls ist, wenn ich die Frage richtig verstehe :

$> find . -type f -mtime -14 | cut -b 3- > deploy.txt

Dies entfernt die ersten Zeichen aus jeder Zeile des Ergebnisses (in Ihrem Fall ./). Wahrscheinlich nicht die beste Lösung, funktioniert aber in Ihrem Szenario.


1

sed ist perfekt für so etwas.

$ find . -type f -mtime -14 find . | sed 's/^\.\///' > deploy.txt

1

Ich weiß nicht, um welche Art von Dateinamen es sich handelt, aber durch Leerzeichen oder Zeilenumbrüche sind die meisten Lösungen hier gefährdet.

Mein Vorschlag wäre, die Parametererweiterung der Shell zu verwenden, um die Zeichen aus jedem Dateinamen zu entfernen:

find . -mtime -14 -exec sh -c 'printf "${0#./}\n"' {} \; >deploy.txt

Wenn Sie Pipes wirklich wirklich mögen, können Sie ein "sicheres" Trennzeichen wie eine Null mit xargs verwenden, um jeden Dateinamen zu erhalten:

find . -mtime -14 -print0 | xargs -0 -n 1 sh -c 'printf "${0#./}\n"' >deploy.txt

Denken Sie daran, dass die Ausgabe NICHT durch Nullen getrennt ist. Obwohl dies für eine Augapfelüberprüfung ausreichend ist, erstellt keine dieser Lösungen eine deploy.txt-Datei, die sicher für die Automatisierung verwendet werden kann, es sei denn, Sie sind sich Ihrer Quelle sehr sicher Dateinamen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.