J'ai de nombreux fichiers texte dans un répertoire et je souhaite supprimer la dernière ligne de chaque fichier du répertoire.
Comment puis-je le faire?
text-processing
files
ThehalfarisedPheonix
la source
la source
Réponses:
Si vous y avez accès
vim
, vous pouvez utiliser:la source
Vous pouvez utiliser ce joli oneliner si vous avez GNU
sed
.Il supprimera la dernière ligne de chaque fichier non masqué dans le répertoire actuel. Le commutateur
-i
pour GNUsed
signifie fonctionner en place et'$ d'
commandesed
de supprimer la dernière ligne ($
signifiant dernière etd
signifiant supprimer).la source
-i
ce qui est un GNUisme, donc c'est théorique, mais je perdrais ma vieille barbe si je ne soulignais pas que certaines anciennes versions desed
ne vous permettent pas de mettre un espace entre le$
et led
(ou, en général, entre le motif et la commande).*(.)
pour glober des fichiers réguliers, je ne connais pas les autres shells.Les autres réponses ont toutes des problèmes si le répertoire contient autre chose qu'un fichier normal ou un fichier avec des espaces / retours à la ligne dans le nom de fichier. Voici quelque chose qui fonctionne malgré tout:
find "$dir" -type f
: rechercher les fichiers dans le répertoire$dir
-type f
qui sont des fichiers réguliers;-exec
exécuter la commande sur chaque fichier trouvésed -i
: éditer les fichiers en place;'$d'
: supprime (d
) la dernière$
ligne ( ).'+'
: indique à find de continuer à ajouter des arguments àsed
(un peu plus efficace que d'exécuter la commande pour chaque fichier séparément, grâce à @zwol).Si vous ne voulez pas descendre dans les sous-répertoires, vous pouvez ajouter l'argument
-maxdepth 1
àfind
.la source
find
ceci est écrit plus efficacementfind $dir -type f -exec sed -i '$d' '{}' '+'
.)-print0
n'est pas présent dans la commande complète, pourquoi le mettre dans l'explication?-depth 0
ne fonctionne pas (findutils 4.4.2), il devrait plutôt l'être-maxdepth 1
.-exec
.Utiliser GNU
sed -i '$d'
signifie lire le fichier complet et en faire une copie sans la dernière ligne, alors qu'il serait beaucoup plus efficace de simplement tronquer le fichier en place (au moins pour les gros fichiers).Avec GNU
truncate
, vous pouvez faire:Si les fichiers sont relativement petits, cela serait probablement moins efficace car il exécute plusieurs commandes par fichier.
Notez que pour les fichiers qui contiennent des octets supplémentaires après le dernier caractère de nouvelle ligne (après la dernière ligne) ou en d'autres termes, s'ils ont une dernière ligne non délimitée , en fonction de l'
tail
implémentation,tail -n 1
ne renverra que ces octets supplémentaires (comme GNUtail
), ou la dernière ligne (correctement délimitée) et ces octets supplémentaires.la source
|wc -c
dans l'tail
appel? (ou a${#length}
)${#length}
ne fonctionnerait pas car il compte les caractères, pas les octets et$(...)
supprimerait le caractère de nouvelle ligne en queue donc${#...}
serait désactivé d'un, même si tous les caractères étaient à un octet.Une approche plus portable:
Je ne pense pas que cela a besoin d' aucune explication ... sauf peut - être que dans ce cas
d
est le même que$d
depuised
par défaut sélectionne la dernière ligne.Cela ne cherchera pas récursivement et ne traitera pas les fichiers cachés (aka dotfiles).
Si vous souhaitez également les modifier, voir Comment faire correspondre * avec des fichiers cachés dans un répertoire
la source
[[]]
à[]
alors il sera entièrement compatible POSIX. ([[ ... ]]
est un bashisme.)[[
n'est pas unOne-liner conforme POSIX pour tous les fichiers commençant récursivement dans le répertoire courant, y compris les fichiers dot:
Pour les
.txt
fichiers uniquement, de manière non récursive:Regarde aussi:
la source