Supprimer le chemin de la sortie de la commande find

29

J'ai un script bash pour déployer du code d'un environnement bêta à un environnement de production mais actuellement je dois ajouter la liste des fichiers à un fichier txt de manière manaully et parfois j'en manque. Fondamentalement, mon script de déploiement cat / loops copie les fichiers. (exportations / importations db également mais ce n'est pas pertinent..lol)

Quoi qu'il en soit, j'aimerais utiliser la findcommande pour générer une liste de fichiers modifiés au cours des 14 derniers jours. Le problème est que je dois supprimer le chemin d'accès ./pour que le script de déploiement fonctionne.

Voici un exemple d'utilisation de la commande find:

trouver . -type f -mtime -14> deploy.txt

Voici la ligne que les chats deploy.txtdans mon script de déploiement:

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

Avez-vous une idée de comment accomplir cela en utilisant le script bash?

Merci!

Mikey1980
la source
3
Y a-t-il une raison pour laquelle vous ne pouvez pas simplement utiliser rsync pour cela? On dirait que vous essayez de réinventer la roue et d'en faire un triangle.
ThatGraemeGuy
point valide cependant avant le déploiement, le deploy.txt est examiné et tout ce qui doit être réparé est supprimé
Mikey1980
1
Peut-être exécuter rsync en --dry-runmode et le publier dans un fichier pour examen?
Zoredache

Réponses:

36

Vous pouvez utiliser l' -printfoption de ligne de commande avec %fpour imprimer uniquement le nom de fichier sans aucune information de répertoire

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

ou vous pouvez utiliser sed pour simplement supprimer le ./

find . -type f -mtime -14 | sed 's|^./||' >deploy.txt
Iain
la source
Je crois que vous devez échapper à la /..
EEAA
5
Pas lorsque vous l'utilisez |comme délimiteur.
user9517 prend en charge GoFundMonica
3
L'utilisation %fsupprimera tous les répertoires, pas seulement ./. Cela interrompra son script de déploiement si l'un des fichiers renvoyés par findse trouve dans des sous-répertoires.
James Sneeringer
2
@Iain Vous devez cependant vous échapper .. Et peut-être mieux d'utiliser une ancre de début de ligne:s|^\./||
James O'Gorman
12
Utilisez %Pau lieu de %f. Cela coupe simplement le chemin indiqué dans la ligne de commande.
TrueY
12

Le ./devrait être inoffensif. La plupart des programmes traiteront /foo/baret /foo/./barcomme équivalents. Je me rends compte que ce n'est pas très joli, mais d'après ce que vous avez publié, je ne vois aucune raison pour laquelle cela ferait échouer votre script.

Si vous voulez vraiment le retirer, sedc'est probablement le moyen le plus propre:

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

Si vous êtes sur un système avec GNU find (par exemple la plupart des systèmes Linux), vous pouvez le faire en une seule fois avec find -printf:

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

Le %Pretourne le chemin complet de chaque fichier trouvé, moins le chemin spécifié sur la ligne de commande, jusqu'à et y compris la première barre oblique. Cela préservera tous les sous-répertoires de votre structure de répertoires.

James Sneeringer
la source
1
Le ./préfixe est en fait une fonctionnalité; sans cela, la sortie des tuyaux vers d'autres commandes ne fonctionnera pas correctement, par exemple pour les noms de fichiers commençant par un tiret.
tripleee
1
@tripleee - Je comprends son utilité, mais OP a spécifiquement demandé comment le retirer car cela causait des problèmes pour son script de déploiement. Bien sûr, il pourrait y avoir de meilleures façons de faire ce qu'il doit faire, mais c'est un trou de lapin bien au-delà de la portée de ce qui a été demandé.
James Sneeringer
7

Pourquoi avez-vous besoin de vous déshabiller ./? C'est valable d'avoir dans un chemin. Alors

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

c'est juste ok!

Mais si vous souhaitez supprimer le nom du répertoire dans find, vous pouvez utiliser l' %Pargument pour-printf .

l'homme trouve (1) dit:

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

Un exemple

$ 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

Attention à la première ligne vide! Si vous voulez l'éviter, utilisez-mindepth 1

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

Eh bien, vous avez quelques options. Vous pouvez utiliser l' -printfoption de recherche pour imprimer uniquement le nom du fichier, ou vous pouvez utiliser un outil comme sed pour simplement supprimer le ./.

# 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/^\.\///'
Zoredache
la source
Pouvez-vous me donner un exemple de son utilisation? Désolé, Linux n'est pas vraiment mon forté
Mikey1980
2
Regardez encore, il y a des exemples.
Zoredache
D'accord - essayez-le, vous n'allez rien faire de mal en combinant find et sed.
EEAA
3

La solution "find -printf" ne fonctionnera pas sur FreeBSD car find n'a pas une telle option. Dans ce cas, AWK peut vous aider. Il renvoie un nom de famille ($ NF), donc il peut fonctionner sur n'importe quelle profondeur.

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

PS: extrait du livre D.Tansley "Programmation shell Linux et Unix"

user221341
la source
2

Une solution rapide, si je comprends bien la question, utilise cutsur la sortie de la findcommande:

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

Cela supprimera le premier aux caractères de chaque ligne du résultat (dans votre cas ./). Probablement pas la meilleure solution, mais fonctionne dans votre scénario.

Alessandro Dotti Contra
la source
1

sed est parfait pour ce genre de chose.

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

Je ne sais pas de quel type de nom de fichier nous parlons, mais tout ce qui comporte des espaces ou des nouvelles lignes met en danger la plupart des solutions.

Ma suggestion serait d'utiliser l'expansion des paramètres du shell pour supprimer les caractères de chaque nom de fichier:

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

Si vous aimez vraiment les pipes, vous pouvez utiliser un délimiteur "sûr", comme un null, avec xargs pour recevoir chaque nom de fichier:

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

N'oubliez pas que la sortie de ceci n'est PAS délimitée par des valeurs nulles, donc bien que cela puisse être suffisant pour une vérification du globe oculaire, aucune de ces solutions ne produit un fichier deploy.txt qui peut être utilisé en toute sécurité pour l'automatisation, à moins que vous ne soyez très sûr de votre source noms de fichiers.

ghoti
la source