La préservation de leader de l'espace blanc lors de la lecture>>l'écriture d'un fichier ligne par ligne dans bash
Je suis en train de faire une boucle par un répertoire de fichiers texte et de les combiner en un seul document. Cela fonctionne très bien, mais le texte fichiers contiennent des extraits de code, et tous mes formatage est se sont effondrés à la gauche. Tous les principaux espaces d'une ligne est supprimée.
#!/bin/sh
OUTPUT="../best_practices.textile"
FILES="../best-practices/*.textile"
for f in "$FILES"
do
echo "Processing $f file..."
echo "">$OUTPUT
cat $f | while read line; do
echo "$line">>$OUTPUT
done
echo >>$OUTPUT
echo >>$OUTPUT
done
Je suis certes qu'un coup de noob, mais après une recherche de haut et de bas, je ne pouvais pas trouver une solution appropriée. Apparemment BASH déteste le premier espace blanc en général.
Vous devez vous connecter pour publier un commentaire.
Au lieu de:
Ce faire:
(Si il ya une raison que vous devez faire les choses, ligne par ligne, il serait bon d'inclure cela dans la question.)
Comme d'autres l'ont souligné, à l'aide de chat ou awk au lieu d'une lecture de l'écho de la boucle est une bien meilleure façon de le faire -- évite le blanc, le parage problème (et quelques autres que vous n'êtes pas encore tombé sur), fonctionne plus rapidement, et au moins avec le chat, c'est tout simplement plus propre code. Néanmoins, j'aimerais prendre un coup de couteau à l'obtention de la lecture de l'écho de la boucle à l'œuvre.
Tout d'abord, le blanc, le parage problème: la commande de lecture automatiquement les trims de l'attaque et de fuite des espaces; ceci peut être corrigé en modifiant la définition de l'espace en définissant la variable IFS à vide. Aussi, lire suppose qu'une barre oblique à la fin de la ligne, la ligne suivante est une continuation, et devrait être ligaturés ensemble avec celui-ci; pour résoudre ce problème, utiliser son -r (raw) du pavillon. Le troisième problème, c'est que de nombreuses implémentations de l'écho d'interpréter les séquences d'échappement dans la chaîne (par exemple, ils peuvent se tourner \n en un véritable saut de ligne); pour résoudre ce problème, utiliser printf à la place. Enfin, tout comme un général de script d'hygiène règle générale, vous ne devriez pas utiliser le chat quand vous n'en avez pas réellement besoin de l'; utilisation de la redirection d'entrée à la place. Avec ces changements, la boucle interne ressemble à ceci:
...il y a aussi un couple de d'autres problèmes avec l'environnement du script: la ligne qui tente de définir les FICHIERS à la liste d'disponibles .textile fichiers a des guillemets autour d'elle, le sens qu'il n'est jamais étendu dans une liste de fichiers. La meilleure façon de le faire est d'utiliser un tableau:
(et toutes les occurrences de $f doit être entre guillemets dans le cas où les noms de fichiers d'avoir des espaces ou d'autres drôles de personnages en eux-devrait vraiment le faire avec $SORTIE, bien que depuis que définies dans le script c'est réellement sans danger à laisser de côté.)
Enfin, il y a un
echo "">$OUTPUT
près du sommet de la boucle sur les fichiers qui va effacer le fichier de sortie à chaque fois à travers (c'est à dire à la fin, il ne contient que la dernière .textile fichier); ce doit être déplacé à l'avant de la boucle. Je ne suis pas sûr si le but ici était de mettre une seule ligne vide au début du fichier, ou trois lignes vides entre les fichiers (et l'un au début et deux à la fin), donc je ne sais pas exactement ce que le remplacement approprié est. De toute façon, voici ce que je peux avec après avoir résolu tous ces problèmes:IFS='' read -r line
n'affecte que le champ interne de séparateur utilisé par leread
de commande et rien à l'intérieur ou après la boucle while? J'ai vuORIG_IFS="$IFS"; ...; IFS="$ORIG_IFS"
, mais ce n'est pas nécessaire dans ce cas, est-il?read
de commande, il ne s'applique qu'une seule commande.c'est trop cher façon de combiner les fichiers.
si vous souhaitez ajouter un blanc( saut de ligne) pour chaque fichier que vous concaténer, utiliser awk
OU
Cela vous permet d'intercaler des retours à la ligne entre chaque fichier d'entrée comme vous l'avez fait dans votre script d'origine:
Noter que
$FILES
est non cotées pour que cela fonctionne (sinon, le supplément de nouvelles lignes apparaissent qu'une seule fois à la fin de la sortie), mais$f
doit être cité pour protéger les espaces dans les noms de fichiers s'ils existent.La bonne réponse, omi, est cette, reproduit ci-dessous:
Remarque que ça va prendre soin de situations où l'entrée est transmise à partir d'une autre commande, et pas seulement à partir d'un fichier existant.
Notez que vous pouvez également simplifier la redirection comme indiqué ci-dessous.