[script zsh] possibilité de faire ça en une ligne ?

possibilité de faire ça en une ligne ? [script zsh] - Codes et scripts - Linux et OS Alternatifs

Marsh Posté le 04-11-2008 à 17:05:09    

Bonjour,
 
je fais ça dans plusieurs scripts :


a=$2
 
for i in `seq 1 $1`; do
 a=$a:h
done


 
Si on fournit les arguments "2" et "/home/toto/desktop" ça renvoie "/home/", donc ça "remonte" de 2 répertoires.
 
Ca marche très bien, mais je trouve ça un peu moche, du coup je me demandais s'il était possible de réaliser la même chose en une ligne, par exemple s'il y a déjà une commande zsh qui fait ça ?
 
Merci d'avance :)
 

Reply

Marsh Posté le 04-11-2008 à 17:05:09   

Reply

Marsh Posté le 05-11-2008 à 16:20:24    

Tu peux utiliser sed pour cela.

 

Ce que tu veux faire au premier niveau :

/home/toto/desktop => /home/toto/


c'est à dire remplacer /desktop par /

  

au second niveau :

/home/toto/desktop => /home/


c'est à dire remplacer /toto/desktop par /

  

au troisième niveau :

/home/toto/desktop => /


c'est à dire remplacer /home/toto/desktop par /

 


Bref au niveau n on remplace les n derniers /toto par /

   

/toto ça s'écrit avec des expressions régulières :
/ =>  le caractère /
[^/]*  =>  n'importe quel caractère qui n'est PAS /, une ou plusieurs fois de suite
Donc /[^/]*

 

/toto/tutu/titi... n fois, c'est pas très dur en repartant du truc précédent :
(/[^/]*){n} : en noir l'expression précédente pour /toto, en bleu le côté 'n fois'

 


Les n derniers /toto/tutu ça s'écrit (en repartant encore du truc précédent) :
(/[^/]*){n}$ : le $ est une ancre présente à la fin de la chaine de caractère. Ainsi on doit trouver "/toto n fois" (en noir) puis la fin de chaine.

 


Soit au final (/[^/]*){n}$

  


Maintenant la syntaxe de sed :

echo "chaine de caractères" | sed 's_ancien truc_nouveau truc_'

 

Le nouveau truc c'est / (cf. plus haut, à chaque niveau on remplace par /)
L'ancien c'est l'expression pour les n derniers /toto/tutu, sauf que pour tout foutre dans sed, on doit utiliser \( au lieu de (  et \{ au lieu de {
C'est (encore) moins lisible du coup :D

  

Au final :

$  echo "/home/toto/desktop" | sed 's_\(/[^/]*\)\{1\}$_/_'
/home/toto/

 

$  echo "/home/toto/desktop" | sed 's_\(/[^/]*\)\{2\}$_/_'
/home/

 

$  echo "/home/toto/desktop" | sed 's_\(/[^/]*\)\{3\}$_/_'
/

  


Bref tout ça pour dire que si tu ne connais pas les expressions régulières c'est pas simple en une ligne je pense  :D

Message cité 2 fois
Message édité par Xavier_OM le 05-11-2008 à 16:24:54

---------------
Il y a autant d'atomes d'oxygène dans une molécule d'eau que d'étoiles dans le système solaire.
Reply

Marsh Posté le 05-11-2008 à 16:28:18    

freewol a écrit :

Bonjour,
 
je fais ça dans plusieurs scripts :


a=$2
 
for i in `seq 1 $1`; do
 a=$a:h
done


 
Si on fournit les arguments "2" et "/home/toto/desktop" ça renvoie "/home/", donc ça "remonte" de 2 répertoires.
 
Ca marche très bien, mais je trouve ça un peu moche, du coup je me demandais s'il était possible de réaliser la même chose en une ligne, par exemple s'il y a déjà une commande zsh qui fait ça ?
 
Merci d'avance :)
 


 
ne jamais utiliser de spécificité liée à un shell dans un script, faire ses shebang avec /bin/sh [:klem3i1]


---------------
uptime is for lousy system administrators what Viagra is for impotent people - mes unixeries - github me
Reply

Marsh Posté le 05-11-2008 à 21:05:26    

Ouais comme ça quand tu te trouve sur une machine où sh est un lien vers bsh, y'a plus rien qui marche (c'est du vécu).

Reply

Marsh Posté le 05-11-2008 à 21:13:58    

matafan a écrit :

Ouais comme ça quand tu te trouve sur une machine où sh est un lien vers bsh, y'a plus rien qui marche (c'est du vécu).


 
bash est compatible sh, si tu utilises pas de "basherie" (comme précisé) ça pose pas de soucis.


---------------
uptime is for lousy system administrators what Viagra is for impotent people - mes unixeries - github me
Reply

Marsh Posté le 05-11-2008 à 22:20:09    

bsh (bourne shell) est bien plus limité que sh

Reply

Marsh Posté le 05-11-2008 à 23:17:56    

chez moi bsh c'est "beanshell". je parle de shells compatibles sh. Et encore une fois, que le shell soit plus limité que sh constitue une spécificité.


---------------
uptime is for lousy system administrators what Viagra is for impotent people - mes unixeries - github me
Reply

Marsh Posté le 06-11-2008 à 08:04:03    

Xavier_OM a écrit :

Tu peux utiliser sed pour cela.
 
Ce que tu veux faire au premier niveau :

/home/toto/desktop => /home/toto/


c'est à dire remplacer /desktop par /
 
 
 
au second niveau :

/home/toto/desktop => /home/


c'est à dire remplacer /toto/desktop par /
 
 
 
au troisième niveau :  

/home/toto/desktop => /


c'est à dire remplacer /home/toto/desktop par /
 
 
Bref au niveau n on remplace les n derniers /toto par /
 
 
 
 
 
/toto ça s'écrit avec des expressions régulières :
/ =>  le caractère /
[^/]*  =>  n'importe quel caractère qui n'est PAS /, une ou plusieurs fois de suite
Donc /[^/]*
 
/toto/tutu/titi... n fois, c'est pas très dur en repartant du truc précédent :
(/[^/]*){n} : en noir l'expression précédente pour /toto, en bleu le côté 'n fois'
 
 
Les n derniers /toto/tutu ça s'écrit (en repartant encore du truc précédent) :
(/[^/]*){n}$ : le $ est une ancre présente à la fin de la chaine de caractère. Ainsi on doit trouver "/toto n fois" (en noir) puis la fin de chaine.
 
 
Soit au final (/[^/]*){n}$
 
Putain, les regexp à chaque fois que j'en vois , ca me fout la migraine ! :D
En tout cas, bravo et merci pour l'explication didactique !
 
 
 
 
Maintenant la syntaxe de sed :

echo "chaine de caractères" | sed 's_ancien truc_nouveau truc_'


 
Le nouveau truc c'est / (cf. plus haut, à chaque niveau on remplace par /)
L'ancien c'est l'expression pour les n derniers /toto/tutu, sauf que pour tout foutre dans sed, on doit utiliser \( au lieu de (  et \{ au lieu de {  
C'est (encore) moins lisible du coup :D
 
 
 
Au final :

$  echo "/home/toto/desktop" | sed 's_\(/[^/]*\)\{1\}$_/_'
/home/toto/
 
$  echo "/home/toto/desktop" | sed 's_\(/[^/]*\)\{2\}$_/_'
/home/
 
$  echo "/home/toto/desktop" | sed 's_\(/[^/]*\)\{3\}$_/_'
/


 
 
 
 
Bref tout ça pour dire que si tu ne connais pas les expressions régulières c'est pas simple en une ligne je pense  :D


Reply

Marsh Posté le 06-11-2008 à 10:06:44    

Xavier_OM a écrit :

Tu peux utiliser sed pour cela.
 
[snip]
 
Au final :

$  echo "/home/toto/desktop" | sed 's_\(/[^/]*\)\{1\}$_/_'
/home/toto/
 
$  echo "/home/toto/desktop" | sed 's_\(/[^/]*\)\{2\}$_/_'
/home/
 
$  echo "/home/toto/desktop" | sed 's_\(/[^/]*\)\{3\}$_/_'
/


 
 
Bref tout ça pour dire que si tu ne connais pas les expressions régulières c'est pas simple en une ligne je pense  :D


 
Ouah, merci pour l'explication détaillée :)
Effectivement c'est assez illisible le code sed ;) Mais à la limite avec un bon commentaire à côté ça peut passer. Surtout qu'apparemment ça serait plus portable que mon bout de code.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed