Ajouter aux files

Je suis un débutant à Linux et j'essaye de résoudre ce problème. J'ai un directory complet de files. Mon but est d'append du text au début du file. Le text qui se trouve au début est le même pour chaque file. C'est ma tentative

#!/bin/bash for file in `find . -type f -executable`;do sed '/\#!/bin/bash\/a Hello Word' done 

Mon script ne fait rien mais plantage S'il vous plaît aidez

 #!/bin/bash for file in `find . -type f -executable`;do sed '/\#!/bin/bash\/a Hello Word' fi done 

Ce script a un grand nombre de problèmes.


Tout d'abord, ce n'est pas un script Bash valide, car vous avez fi sans aucun correspondant if .


Stylistiquement (après avoir enlevé la ligne), je voudrais enlever la ligne vide avant de done et append un espace avant do . Mais c'est relativement banal.


Maintenant, en ce qui concerne les meilleures pratiques, vous utilisez des backticks pour la substitution de commands plutôt que la forme moderne recommandée, $(...) . Les backticks sont pris en charge uniquement pour des raisons historiques et ne sont pas recommandés pour les nouveaux scripts; voir:

  • Les backticks (c.-à-d. `Cmd`) dans * sh shells ont-ils été dépréciés?

Vous avez un problème de robustesse en ce sens que vous parcourez le résultat de la find – une très mauvaise idée et totalement inutile. Votre script se casse sur n'importe quel nom de file contenant des espaces ou des caractères spéciaux. Voir:

  • Pourquoi boucler la mauvaise pratique de sortie de la découverte? )

Si vous souhaitez que votre script soit portable, vous devez vous en tenir aux fonctionnalités spécifiées POSIX dans la mesure du possible. En particulier, le -executable primaire -executable à find n'est pas spécifié par POSIX . Envisagez d'utiliser -perm +700 place.

En outre, dans le domaine de la portabilité, l'utilisation de la command "append" à Sed ( a ) sans séquence suivante \<newline> fonctionne dans GNU Sed, mais n'est pas standard.


Vous définissez la variable de file dans votre boucle for au nom de chaque file (en supposant qu'il n'y a pas de caractères spéciaux ou d'espaces dans les noms de files, ce qui fera que la variable de file contiendra quelque chose qui n'est pas un nom de file) file variable.

Votre command Sed ne reçoit aucun file à exécuter, donc elle tentera de s'exécuter sur une input standard. Ainsi, lorsque vous exécutez le script, il attend simplement l'input.


Votre script Sed lui-même est incorrect, indépendamment du fait qu'il manque un nom de file pour fonctionner.

Si vous utilisez / tant que délimiteur pour une expression régulière (ce qui est le plus courant), vous devez ignorer l'échappement de toutes les instances de / qui se produisent dans l'expression rationnelle. La seule partie de votre command qui sera lue comme une regex est /\#!/ Et le rest (commençant par bin ) sera interprété comme une command Sed.

Au lieu de cela, la solution habituelle serait de replace chaque / autre que le délimiteur final par \/ . (Je vois que vous n'avez échappé qu'à la dernière barre, qui ne devrait pas être échappée.)

Il y a une caractéristique peu connue dans Sed , que vous pourriez utiliser à votre avantage ici. Tout caractère (autre qu'une barre oblique inverse ou une nouvelle ligne) peut être utilisé comme délimiteur d'expressions rationnelles, plutôt que d'utiliser uniquement une barre oblique. Ainsi, au lieu d'utiliser /#!\/bin\/bash/ comme adresse Sed, vous pourriez utiliser l'équivalent \:#!/bin/bash:


Maintenant, si vous avez traité tous les points ci-dessus, vous aurez un script de travail. Il ne fait peut-être pas ce que vous voulez faire, mais il fera quelque chose . Un tel script ressemblerait à ceci:

 #!/bin/bash find . -type f -perm -700 -exec sed '\:#!/bin/bash:a\ Hello World' {} + 

Que fait ce script? Il search récursivement le directory courant pour tous les files avec le bit exécutable (pour le propriétaire), et pour chaque file, imprime le file entier avec le text Hello World ajouté après les lignes contenant le text #!/bin/bash .

Sed n'est pas conçu pour l'édition de files; c'est le Stream EDitor. GNU Sed vous permettra de modifier les files en place en utilisant le commutateur -i , mais j'utiliserais simplement l' outil standard ex pour l'édition de files.


Mais il y a un autre point ici. Si vous voulez append la ligne Hello World dans un script Bash, cela ne fera rien, car Hello n'est pas un nom de command valide. Peut-être que vous voulez imprimer le text "Hello World" dans le script Bash, en d'autres termes pour append l' echo "Hello World , qui pourrait avoir du sens.

Maintenant nous sums dans le domaine de clarifier plus exactement ce que votre script est censé faire.


Le script final

Donc, mon énoncé plus précis des spécifications de ce script sont:

  • Le script doit find tous les files réguliers dans le directory courant (ou tout sous-directory récursif) qui ont le bit exécutable défini pour le propriétaire.
  • Pour chaque file, le script vérifie si la première ligne du file est exactement égale à la string #!/bin/bash .
  • Seulement pour les files avec cette première ligne exacte, le script doit insert l' echo "Hello World" text exact echo "Hello World" , suivi d'un caractère de nouvelle ligne, après la première ligne du file. (Cette modification doit être sauvegardée dans le file, pas imprimée sur sortie standard.)

Voici un script correspondant à ces spécifications exactes, en utilisant uniquement les outils et fonctionnalités POSIX:

 #!/bin/sh find . -type f -perm -700 -exec sh -c ' for f do head -n 1 "$f" | grep -qFx "#!/bin/bash" && printf "%s\n" "1a" "echo \"Hello World\"" . x | ex "$f" done ' find-sh {} + 

Qu'est-ce que vous essayez d'atteindre? pour find les scripts exécutables, utilisez la command ci-dessous

 find . -type f -perm /u+x,g+x,o+x | while read file do filename=$(echo ${file} | awk -F/ '{print $NF}') echo "File Name : ${filename}" done 

Si vous essayez d'append Hello World après la ligne shebang, votre command sed doit être

  sed '/\#!/bin/bash/a Hello Word' ${file} 

si vous souhaitez effectuer les modifications dans le file lui-même, ajoutez -i dans la command sed

find . -type f -executable -exec sed '/^#!\/bin\/bash/a Hello World' {} \;