Jump to content

Archived

This topic is now archived and is closed to further replies.

lorinc

[Tuto][débutant] 10 exercices de bash

Recommended Posts

allez, 2 solutions pour la prise de tete de hier soir lorinc :)

Une solution pas très jolie qui utilise read pour lire les lignes du fichier rentré en flux.

#!/bin/bash

fic1=$1
fic2=$2

compt=0

while read i
do
       while read j
       do
               if [ "$i" = "$j" ]
               then
                       compt=`expr $compt + 1`
               fi
       done  < $fic2
done < $fic1

echo $compt;

Une solution un peu plus chiadée, mais loin d'etre parfaite. A quand les getopt pour afficher le nombre de lignes communes au lieu du nombre de lignes de differences :)

#!/bin/bash

fic1=$1
fic2=$2

n1=`cat $fic1 | wc -l`
n2=`cat $fic2 | wc -l`

compt=0
lines=$(cat $fic1 | tr -s "\n" | wc -l | cut -d " " -f1)

for i in `head -n $n1 ${fic1}`
do
       for j in `head -n $n2 ${fic2}`
       do
               if [ $j = $i ]
               then
                       compt=`expr $compt + 1`;
               fi
       done
done
echo `expr $lines - $compt`

Share this post


Link to post
Share on other sites

punaise, j'y ai pensé ce matin dans la voiture en me disant : "t'es con, pourquoi tu ne fais pas 2 boucles..."

bravo :non:

Share this post


Link to post
Share on other sites

Pas mal pas mal.

Juste une ou deux remarques.

Pourquoi ne pas utiliser cat à la place d' echo?

Je m'explique:

Remplacer :

   echo "ul {" > defaut.css
  echo "padding:0; " >> defaut.css
  echo "margin:0; " >> defaut.css
  echo "list-style-type:none; " >> defaut.css
  echo "}" >> defaut.css
  echo "" >> defaut.css
  echo "a.gal span {" >> defaut.css
  echo "position:absolute; " >> defaut.css
  echo "width:1px; " >> defaut.css
  ...
  echo "}" >> defaut.css

Par


cat <<EOF > default.css
ul {
padding:0;
margin:0;
list-style-type:none;
}

a.gal span {
position:absolute;
width:1px;
...
}

EOF

C'est plus simple, et inutile d'utiliser "\" à tout bout de champ.

Sinon, dans ton script, je remplacerais:

   if [ ! -d $DEST_DIR ]
  then
      err "<EE> creation du repertoire de miniature impossible"
  fi

Par

[ -d $DEST_DIR ] || err "<EE> creation du repertoire de miniature impossible"

Tu peux l'appliquer à plusieurs autres endroits, mais ca c'est plus une question de gouts.

Enfin, sur la correction du premier exo, je remplacerais

cp $1 $2

par

cp -- "$1" "$2"

-- = fin implicite de toutes les options.

Comment marcherait ton script sinon si $1 ou $2 vaut "-test" ? Si il y a des espaces dans $1 ou $2?

Sinon très bon tuto :francais:

Share this post


Link to post
Share on other sites
Pourquoi ne pas utiliser cat à la place d' echo?

Je m'explique:

Remplacer :

   echo "ul {" > defaut.css
  echo "padding:0; " >> defaut.css
  echo "margin:0; " >> defaut.css
  echo "list-style-type:none; " >> defaut.css
  echo "}" >> defaut.css
  echo "" >> defaut.css
  echo "a.gal span {" >> defaut.css
  echo "position:absolute; " >> defaut.css
  echo "width:1px; " >> defaut.css
  ...
  echo "}" >> defaut.css

Par


cat <<EOF > default.css
ul {
padding:0;
margin:0;
list-style-type:none;
}

a.gal span {
position:absolute;
width:1px;
...
}

EOF

C'est plus simple, et inutile d'utiliser "\" à tout bout de champ.

Juste pour dire qu'il y a aussi moyen de regrouper les echo...

{
  echo "ul {"
  echo "padding:0;"
  echo "margin:0;"
  echo "list-style-type:none;"
  echo "}"
  echo ""
  echo "a.gal span {"
  echo "position:absolute;"
  echo "width:1px; "
  ...
  echo "}"
} > defaut.css

(mais je pense que moi j'aurait utilisé un cat aussi)

Share this post


Link to post
Share on other sites

voilà, j'ai ajouté vos corrections/conseils. merci :transpi:

n'hésitez pas à proposer d'autres choses, ou même carrément des exos. Par contre il faut que ça reste simple, le plus simple possble en fait. histoire de garder l'étiquette [Débutant] :transpi:

Share this post


Link to post
Share on other sites
voilà, j'ai ajouté vos corrections/conseils. merci :ouioui:

n'hésitez pas à proposer d'autres choses, ou même carrément des exos. Par contre il faut que ça reste simple, le plus simple possble en fait. histoire de garder l'étiquette [Débutant] :yes:

Mince, j'avais quelques idées pour des trucs plus avancés... :byebye:

(sed, awk, gestion avancée des variables, shift, etc...)

Enfin bon, si j'arrive à faire un truc pas trop compliqué je poste :craint:

Share this post


Link to post
Share on other sites

bien ouej, on pourrait continuer qq bonnes idées et se faire des propositions d'amélioration / optimisation ...

je donne un exemple proche (j'ai programmé ça à l'arrache ça se voit un peu).

je suis l'heureux possesseur d'un Tvix (disque dur externe multimédia) qui affiche en fond d'écran le fichier tvix.jpg.

Dans ma collection bien classée de fichiers son, j'ai des fichiers "artist.jpg" pour une photo de l'artiste, et "front.jpg" comme pochette de l'album (un rep par artiste, avec un sous-répertoire par album).

j'ai donc écrit des scripts à la va-vite pour parcourir l'arborescence et convertir en rafale tous les nouveaux fichiers artist.jpg et album.jpg en tvix.jpg (l'image en grand assombrie pour servir de fond, et l'image en petit dans un endroit où le texte ne s'affiche pas) :

le script de conversion est bateau :

 cat /usr/local/bin/tvix_dopic
#!/bin/sh
#

echo "TViXing `pwd`/$1"

BIG_SIZE="720x480!"
SMALL_SIZE=160x106
SMALL_POS=+8+160

# CORRECT="-gamma 2.4"
# CORRECT="-level 0%,69%,0.5"
CORRECT="-modulate 30,60,100"

convert -resize $BIG_SIZE $CORRECT "$1" _tvix_fond.jpg
convert -resize $SMALL_SIZE "$1" _tvix_small.jpg

composite -geometry $SMALL_POS _tvix_small.jpg _tvix_fond.jpg tvix.jpg

rm _tvix_fond.jpg
rm _tvix_small.jpg

maintenant, pour traiter dans toute l'arborescence, d'une seule passe, j'avais deux solutions :

un find, ou un script qui fonctionne en récurrent.

Mais j'ai essentiellement un gros problème : la gestion des espaces et des caractères spéciaux dans les titres ... donc j'ai fait ça CRADO en utilisant du awk :

#!/bin/sh
#
# en entrée le nom de l'image à traiter (front.jpg ou artist.jpg, en général)

script=tvix.sh
tmp=/tmp/tvix.tmp

> $script
name=$1
command="/usr/local/bin/tvix_dopic $name"

find . -name $name > $tmp
 awk -v com="$command" '\
{ x=split($0,tab,"/"); \
  fname=tab[x];  \
  printf("cd \"");  \
  for (i=1; i<x; i++) \
    { printf(tab[i]"/"); } \
 printf("\"; [ tvix.jpg -nt %s ] || %s; cd -\n",fname,com); 
}' $tmp  >> $script

rm $tmp
sh $script
rm $script

bien assis ?

(j'ai indenté le script awk pour plus de lisibilité)

le name=$1 est juste pour plus de lisibilité

je fais un find pour lister tous les fichiers dont le nom est $name. Pourquoi je ne fais pas un --exec dans la foulée ? parceque le script est trop compliqué, il perd la valeur de {} en cours de route !!

j'ai donc un fichier texte ($tmp) avec une ligne par fichier.

le script awk fait la chose suivante : il génère la ligne de script qui fait

"je vais dans chaque répertoire (tout ce qu'il y a entre le début de ligne et le dernier "/"), si le fichier tvix.jpg n'est pas plus jeune (-nt) que le fichier que je traite (ce qui inclue le cas où le tvix.jpg n'existe pas) je lance la commande, puis je reviens dans le répertoire d'origine (cd -)

Comme j'ai toujours le pb d'espaces, la commande dirname qui aurait pu mettre secourable ne marche pas, d'où mon affreux morceau de awk.

Enfin je préfère différer l'exécution en relisant éventuellement mon $script avant de l'exécuter (pour du débug)...

Voilà tout commentaire bienvenu !!

edit> je vois déjà qq trucs

* positionner un FS="/" au début du script awk, ce qui m'éviterai le split

* tout écrire en Perl (c'est malin, ça :chinois:

Share this post


Link to post
Share on other sites

bien assis ?

(j'ai indenté le script awk pour plus de lisibilité)

le name=$1 est juste pour plus de lisibilité

je fais un find pour lister tous les fichiers dont le nom est $name. Pourquoi je ne fais pas un --exec dans la foulée ? parceque le script est trop compliqué, il perd la valeur de {} en cours de route !!

j'ai donc un fichier texte ($tmp) avec une ligne par fichier.

le script awk fait la chose suivante : il génère la ligne de script qui fait

"je vais dans chaque répertoire (tout ce qu'il y a entre le début de ligne et le dernier "/"), si le fichier tvix.jpg n'est pas plus jeune (-nt) que le fichier que je traite (ce qui inclue le cas où le tvix.jpg n'existe pas) je lance la commande, puis je reviens dans le répertoire d'origine (cd -)

Comme j'ai toujours le pb d'espaces, la commande dirname qui aurait pu mettre secourable ne marche pas, d'où mon affreux morceau de awk.

Enfin je préfère différer l'exécution en relisant éventuellement mon $script avant de l'exécuter (pour du débug)...

Voilà tout commentaire bienvenu !!

Ba je sais pa si ca peut t'aider mais parfois il est utile d'utiliser read avec find.

Un exemple à la con :

find . -name $name|while read chemin_fichier; do
nom_rep=$(dirname "$chemin_fichier")
nom_fichier=$(basename "$chemin_fichier")
echo "Nom fichier : $nom_fichier . Chemin fichier : $nom_rep"
done

Ca devrait passer.

Sinon lorinc, ton exo 1 ne prend toujours pas bien en compte les noms de fichiers avec des espaces. Pense aux "".

Share this post


Link to post
Share on other sites
* tout écrire en Perl (c'est malin, ça :chinois:

:roll:

Mais après c'est plus vraiment des exos bash :transpi:

Share this post


Link to post
Share on other sites

Juste pour filer un petit lien qui contient:

- un memo sur le shell

- deux memos sur les commandes Unix

- un dernier mémo sur quelques commandes de bases pour l'administration Linux

Mémos ici-

Share this post


Link to post
Share on other sites

pas mal ton read, What, j'avais zappé cette commande... je fais tester de suite ...

je confirme ça marche bien ! bon je donner une version améliorée de mon script ASAP

edit>

#!/bin/sh
function traite() {

find . -name $name | while read chemin_fichier; do
nom_rep=$(dirname "$chemin_fichier")
nom_fichier=$(basename "$chemin_fichier")

cd "$nom_rep"
[ tvix.jpg -nt $nom_fichier ] || /usr/local/bin/tvix_dopic $nom_fichier
cd -

done

}

name=front.jpg
traite
name=artist.jpg
traite

effectivement c'est beaucoup plus propre ...

:arrow: what :arrow:

Share this post


Link to post
Share on other sites

tiens je me suis écrit ça sous le coude entre midi et deux :

#!/bin/sh

[ -d $1 ] || echo "syntax : $0 <dir>"

mpg123 -n 0 -v -t $1/* 2>&1 | \
grep Frame | cut -d "[" -f3- | cut -d"]" -f1 | \
awk 'BEGIN { m=0; s=0; FS=":" } { m+=$1; s+=$2; } END { while (s>60) { m++; s-=60; }; printf("%2i:%2.2f\n",m,s) }'

en résumé, ça vous donne pour un répertoire de MP3 la durée totale des morceaux...

intéressant pour préparer ses compiles

$/usr/local/bin/check_duration.sh C\ôte\ d\'Ivoire\Prudencia\ 2005

79:45:30

Share this post


Link to post
Share on other sites
effectivement c'est beaucoup plus propre ...

:francais: what :chinois:

Héhé c'est mon metier :byebye:

Un petit plus sur l'utilisation de read, il peut être utilisé comme un mini awk:

$ egrep -v '^#|^$' /etc/hosts|while read adresse noms_hote; do echo -e "Adresse : $adresse \nNoms d'hotes : $noms_hote"; done

Adresse : 127.0.0.1
Noms d'hotes : localhost
Adresse : ::1
Noms d'hotes : localhost ipv6-localhost ipv6-loopback
Adresse : fe00::0
Noms d'hotes : ipv6-localnet
Adresse : ff00::0
Noms d'hotes : ipv6-mcastprefix
Adresse : ff02::1
Noms d'hotes : ipv6-allnodes
Adresse : ff02::2
Noms d'hotes : ipv6-allrouters
Adresse : ff02::3
Noms d'hotes : ipv6-allhosts
[...]

On peut changer le séparateur en positionant la variable IFS.

Sinon, Tuxxx, à quand ton topic plus avancé sur le shell (le meilleur ami de l'admin)?

EDIT: sanderman, n'oublie pas de mettre le $1 de ton script entre quote(""), ca améliore la gestion des espaces.

Share this post


Link to post
Share on other sites

allez, 2 solutions pour la prise de tete de hier soir lorinc :)

Une solution pas très jolie qui utilise read pour lire les lignes du fichier rentré en flux.

#!/bin/bash

fic1=$1
fic2=$2

compt=0

while read i
do
	while read j
	do
			if [ "$i" = "$j" ]
			then
					compt=`expr $compt + 1`
			fi
	done  < $fic2
done < $fic1

echo $compt;

Une solution un peu plus chiadée, mais loin d'etre parfaite. A quand les getopt pour afficher le nombre de lignes communes au lieu du nombre de lignes de differences :)

#!/bin/bash

fic1=$1
fic2=$2

n1=`cat $fic1 | wc -l`
n2=`cat $fic2 | wc -l`

compt=0
lines=$(cat $fic1 | tr -s "\n" | wc -l | cut -d " " -f1)

for i in `head -n $n1 ${fic1}`
do
	for j in `head -n $n2 ${fic2}`
	do
			if [ $j = $i ]
			then
					compt=`expr $compt + 1`;
			fi
	done
done
echo `expr $lines - $compt`

j'ai trouvé un peu moins esotérique pour lire une liste de noms de fichier avec espaces :

ls monrepertoirealister |
while read monFichier
do 
echo $monFichier
done

Share this post


Link to post
Share on other sites

Super topic :mdr:

Moi qui est tout perdu en Bash et autre language shell (comme ksh et le reste ...), bon j'y connaissait pas grand non plus,mais la je vais m'y remettre dès que j'ai du temps chez moi ...

Merci encore lorinc :francais:

Share this post


Link to post
Share on other sites

×
×
  • Create New...