Est-il possible de se référer aux index dans $@
? Je ne trouve aucune référence à utiliser comme celle-ci dans le wiki de GrayCat , et le Guide de script avancé et d' autres attribuent cela à une variable différente avant de le modifier à la place.
$ echo ${@[0]}
-bash: ${@[0]}: bad substitution
Le but est DRY : le premier argument est utilisé pour une chose, et le reste pour autre chose, et je voudrais éviter de dupliquer le code pour normaliser, le $@
tableau ou pour créer une fonction distincte pour cela (bien qu'à ce que c'est probablement la solution la plus simple).
Clarification: l'objectif était de modifier les valeurs de la longueur variable $@
pour faciliter le débogage du code . La version actuelle est un peu trop hacky à mon goût, même si elle fonctionne même pour des chemins bizarres comme
$'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'
Mise à jour : il semble que ce ne soit pas possible. Le code utilise maintenant à la fois le code et la duplication des données, mais au moins cela fonctionne:
path_common()
{
# Get the deepest common path.
local common_path="$(echo -n "${1:-}x" | tr -s '/')"
common_path="${common_path%x}"
shift # $1 is obviously part of $1
local path
while [ -n "${1+defined}" ]
do
path="$(echo -n "${1}x" | tr -s '/')"
path="${path%x}"
if [[ "${path%/}/" = "${common_path%/}/"* ]]
then
shift
else
new_common_path="${common_path%/*}"
[ "$new_common_path" = "$common_path" ] && return 1 # Dead end
common_path="$new_common_path"
fi
done
printf %s "$common_path"
}
Bounty s'adresse à tous ceux qui peuvent se débarrasser de la duplication de code pour réduire les barres obliques en double ou la duplication des données à conserver $1
et les autres paramètres, ou les deux, tout en conservant une taille raisonnable et en réussissant tous les tests unitaires:
test "$(path_common /a/b/c/d /a/b/e/f; echo x)" = /a/bx
test "$(path_common /long/names/foo /long/names/bar; echo x)" = /long/namesx
test "$(path_common / /a/b/c; echo x)" = /x
test "$(path_common a/b/c/d a/b/e/f ; echo x)" = a/bx
test "$(path_common ./a/b/c/d ./a/b/e/f; echo x)" = ./a/bx
test "$(path_common $'\n/\n/\n' $'\n/\n'; echo x)" = $'\n/\n'x
test "$(path_common --/-- --; echo x)" = '--x'
test "$(path_common '' ''; echo x)" = x
test "$(path_common /foo/bar ''; echo x)" = x
test "$(path_common /foo /fo; echo x)" = x
test "$(path_common $'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n' $'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'; echo x)" = $'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'x
test "$(path_common /foo/bar //foo//bar//baz; echo x)" = /foo/barx
test "$(path_common foo foo; echo x)" = foox
test "$(path_common /fo /foo; echo x)" = x
Réponses:
POSIX
Pour normaliser les barres obliques dans tous les paramètres, je vais utiliser l'astuce de l'argument rotatif: décaler
$1
, le transformer et mettre le résultat à la fin de la liste des paramètres. Si vous faites cela autant de fois qu'il y a de paramètres, vous avez transformé tous les paramètres et vous les avez remis en ordre.Pour la deuxième partie du code, j'ai changé votre logique pour être moins déroutante: la boucle externe itère sur les paramètres, et la boucle interne itère sur les composants du chemin.
for x; do … done
itère sur les paramètres de position, c'est un idiome pratique. J'utilise une manière compatible POSIX de faire correspondre une chaîne à un modèle: lacase
construction.Testé avec dash 0.5.5.1, pdksh 5.2.14, bash 3.2.39, bash 4.1.5, ksh 93s +, zsh 4.3.10.
Note latérale: il semble y avoir un bogue dans bash 4.1.5 (pas dans 3.2): si le modèle de cas est
"${common_path%/}"/*
, l'un des tests échoue.bash, ksh
Si vous êtes en bash (ou ksh), vous pouvez utiliser des tableaux - je ne comprends pas pourquoi vous semblez vous limiter aux paramètres de position. Voici une version qui utilise un tableau. Je dois admettre que ce n'est pas particulièrement plus clair que la version POSIX, mais cela évite le brassage initial n ^ 2.
Pour la partie de normalisation de barre oblique, j'utilise la construction ksh93
${foo//PATTERN/REPLACEMENT}
pour remplacer toutes les occurrences dePATTERN
in$foo
parREPLACEMENT
. Le modèle+(\/)
doit correspondre à une ou plusieurs barres obliques; under bash,shopt -s extglob
doit être en vigueur (de manière équivalente, commencer bash avecbash -O extglob
). La constructionset ${!a[@]}
définit les paramètres positionnels sur la liste des indices du tableaua
. Cela fournit un moyen pratique d'itérer sur les éléments du tableau.Pour la deuxième partie, j'ai la même logique de boucle que la version POSIX. Cette fois, je peux l'utiliser
[[ … ]]
car tous les obus ciblés ici le supportent.Testé avec bash 3.2.39, bash 4.1.5, ksh 93s +.
zsh
Malheureusement, zsh n'a pas la
${!array[@]}
fonctionnalité pour exécuter la version ksh93 telle quelle. Heureusement, zsh a deux fonctionnalités qui font de la première partie un jeu d'enfant. Vous pouvez indexer les paramètres positionnels comme s'il s'agissait du@
tableau, il n'est donc pas nécessaire d'utiliser un tableau intermédiaire. Et zsh a une construction d'itération de tableau :"${(@)array//PATTERN/REPLACEMENT}"
effectue le remplacement de modèle sur chaque élément de tableau à son tour et évalue le tableau de résultats (de manière confuse, vous avez besoin des guillemets doubles même si le résultat est composé de plusieurs mots; il s'agit d'une généralisation de"$@"
). La deuxième partie est essentiellement inchangée.Cas de test
Mes solutions sont testées et commentées de manière minimale. J'ai changé la syntaxe de vos cas de test pour analyser les shells qui n'en ont pas
$'…'
et signaler les échecs de manière plus pratique.la source
Pourquoi n'utilisez-vous pas simplement $ 1, $ 2 .. $ 9, $ {10}, $ {11} .. et ainsi de suite? C'est encore plus SEC que ce que vous essayez de faire :)
En savoir plus sur la relation entre $ number et $ @:
$ @ peut être considéré comme un raccourci pour "tous les éléments d'un tableau contenant tous les arguments"
Donc, $ @ est une sorte de raccourci de $ {args [@]} (args ici est un tableau "virtuel" contenant tous les arguments - pas une vraie variable, remarquez)
$ 1 est $ {args [1]}, $ 2 est $ {args [2]}, etc.
Lorsque vous avez frappé [9], utilisez une accolade: $ {10} est $ {args [10]}, $ {11} est $ {args [11]}, et ainsi de suite.
Utiliser indirectement un argument de ligne de commande
Exemple:
la source
${args[$i]}
.Je pense que ce que tu veux c'est
shift
la source
Je ne sais pas très bien pourquoi vous n'utilisez pas seulement 1 $ 2 $, etc. mais… Cela peut convenir à vos besoins.
production
set
fonctionne de tout ce qui le suit, pour créer $ 1, $ 2 .. etc .. Cela remplacera bien sûr les valeurs d'origine, alors soyez conscient de cela.la source
eval
certains estiment êtreevil
... (peut-être à cause de l'orthographe :) ... Sieval
est "mauvais", alors $ {! Var} est-il également "mauvais"? ... Pour moi, c'est juste une partie du langage, et une partie utile, à cela .. mais je préfère définitivement $ {! Var} ...Remarque Je prends en charge les espaces dans les noms de fichiers.
J'ai ajouté un cas de test pour les noms de fichiers avec des espaces et corrigé 2 tests auxquels il manquait un premier /
la source