J'ai des chaînes sous la forme de wva/sia/e1
, bct/e2
, sv/de/e11
. C'est toujours <Part1>/e<NUM>
ou <Part1>/<Part2>/e<NUM>
. Ce que je veux, c'est raccourcir les chaînes en conservant les premières lettres des parties et en amerrissant les barres obliques et e:
wva/sia/e1 > ws1
bct/e2 > b2
sv/de/e11 > sd11
Comment puis-je faire cela dans un script sh?
Edit: La chaîne représente un nom de travail:
[...]
job_name=$1 # e.g. 'wva/sia/e1'
job_name=cut_name(job_name) # e.g. 'ws1'
[...]
Sous la forme d'un script comme ce que vous demandez:
#!/usr/bin/env python3
import sys
# read the input, split by /
st = sys.argv[1].split("/")
# get the first char of all sections *but* the last one
# add the last *from* the first character
print("".join([s[0] for s in st][:-1])+st[-1][1:])
Notez que cela fonctionne pour n'importe quelle longueur, par exemple:
wva/sia/bct/wva/sia/e1
va devenir
wsbws1
tant que la dernière section se termine par /e<num>
rearrange.py
Exécutez-le avec la chaîne comme argument, par exemple:
python3 /path/to/rearrange.py wva/sia/e1
> ws1
Le script s'explique à peu près tout seul, mais est également commenté.
Disons simplement que nous n'avons pas besoin d'un script complet. Bash a suffisamment de capacités pour nous permettre de nous en sortir avec une seule ligne. En voici un:
bash-4.3$ (read -r var ;IFS='/'; printf "%c" ${var%/*};echo ${var##*[^0-9]}) <<< "sv/de/e11"
sd11
Qu'est-ce qui se passe ?
( )
autour de la commande entière<<<
pour envoyer une entrée, et la commande subshell l'obtient via read -r var
et la stocke dans la variable var
IFS='/'
de sorte que le sous-shell divise var
en éléments distincts dans le séparateur /
. Ceci est important pour le fractionnement de Word.${var%/*}
pour supprimer la dernière partie avant /
. Dans l'exemple ci-dessus, il s'agirait de e11
printf "%c"
verra le résultat de ${var%/*}
comme sv de
en raison du fractionnement du mot et de la suppression du suffixe mentionnés ci-dessus (magie, oui). En raison de la façon dont printf
mots, %c
n’imprimera que le premier caractère, mais il le fera pour chaque argument de ligne de commande qu’il reçoit. Ainsi, pour sv de
, il affichera s
et d
. L'impression est faite sans nouvelle ligne, donc il semble que les caractères sont entrés dans l'ordreecho ${var##*[^0-9]}
utilise la suppression de préfixe pour supprimer tous les caractères non numériques de la chaîne d'entrée donnée, obtenant ainsi uniquement les derniers chiffres.Il existe une autre approche unique, qui est un peu plus explicite et naturelle pour les programmeurs de type C.
bash-4.3$ (read -r inp;IFS='/';arr=( $inp ); for ((i=0;i<$(( ${#arr[@]} -1 ));i++));do printf "%s" ${arr[$i]:0:1};done;printf "%s\n" ${inp##*[^0-9]}) <<< "sv/de/e11"
sd11
Quelle est cette magie? Voici une explication:
()
autour de la commande entière.<<<
pour envoyer l'élément souhaité dans le flux stdin de la commande. La commande l'obtient via la commande read -r inp
et le stocke dans la variable inp
IFS
afin de pouvoir tout décomposer en un tableau.for ((initial condition; test condition; post condition)) ; do ... done
$(( ${#arr[@]} - 1 ))
est un développement arithmétique dans lequel on soustrait 1 de la longueur du tableau ${#arr[@]}
printf "%s" ${arr[$i]:0:1}
nous permet d'utiliser le développement de paramètres dans lequel nous n'imprimons que le premier caractère de chaque élément, et printf "%s"
l'imprime sans nouvelle ligne, ainsi il semble que nous imprimions chaque lettre sur la même ligne.${#*[^0-9]}
Puisque la question demande un script Shell, en voici un dans bash
4.3, qui est presque la même approche que ci-dessus, mais plus explicite:
#!/bin/bash
IFS='/'
items=( $1 )
counter=1
for i in ${items[@]}
do
if [ $counter -eq ${#items[@]} ];
then
# note the space before -1
printf "%s\n" "${i##*[^0-9]}"
else
printf "%s" "${i:0:1}"
fi
counter=$(($counter + 1))
done
La façon dont cela fonctionne est comme suit:
/
et autorisons bash à fractionner le mot afin de décomposer la chaîne en un tableau appelé items
${items[@]}
tout en gardant une trace de l'élément auquel nous nous trouvons à l'aide de la variable counter et connaissant le nombre d'éléments du tableau (la partie ${#items[@]}
).if-statement
est ce qui nous permet de choisir un caractère spécifique dans chaque élément. En utilisant le paramètre de développement, premier caractère via${i:0:1}
. En utilisant la suppression du préfixe le plus long ${variable##prefix}
, nous supprimons tous les caractères non numériques de la dernière chaîne de printf "%s\n" "${i##*[^0-9]}"
.Ici c'est en action:
$ ./shorten_string.sh "wva/sia/e1"
ws1
$ ./shorten_string.sh "bct/e2"
b2
$ ./shorten_string.sh "sv/de/e11"
sd11
OK, pas un script, mais vous pouvez le mettre dans un script (cela aussi est très inélégant puisque je n'ai pas réussi à traiter les deux formulaires avec une seule commande)
$ sed -r 's:(.).*/(.).*/e([0-9]+):\1\2\3:;s:(.).*/e([0-9]+):\1\2:' file
ws1
b2
sd11
-r
utilise EREs:old:new:
remplace old
par new
.*
un nombre quelconque de caractères(.)
enregistrer un caractère dans cette position([0-9]+)
enregistrer au moins un chiffre ici;
sépare les commandes, comme dans le shell\1
référence arrière aux caractères enregistrés avec ()