¿Es posible hacer referencia a índices en $@
? No puedo encontrar ninguna referencia para usar como la siguiente en ninguna parte de la wiki de GrayCat , y la Guía avanzada de secuencias de comandos y otros asignan esto a una variable diferente antes de modificarla.
$ echo ${@[0]}
-bash: ${@[0]}: bad substitution
El objetivo es SECO : el primer argumento se usa para una cosa, y el resto para otra cosa, y me gustaría evitar duplicar el código para normalizar, la $@
matriz o crear una función separada para esto (aunque en este momento punto es probablemente la salida más fácil).
Aclaración: El objetivo era modificar los valores de la longitud variable $@
para facilitar la depuración del código . La versión actual es demasiado hacky para mi gusto, aunque funciona incluso para caminos extraños como
$'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'
Actualización : Parece que esto no es posible. El código ahora usa código y duplicación de datos, pero al menos funciona:
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 se dirige a cualquiera que pueda deshacerse de la duplicación de código para colapsar las barras diagonales duplicadas o la duplicación de datos para mantener $1
y los otros parámetros, o ambos, mientras mantiene el código de un tamaño razonable y realiza todas las pruebas unitarias:
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
Respuestas:
POSIX
Para normalizar las barras diagonales en todos los parámetros, usaré el truco del argumento giratorio:
$1
desactivar, transformar y poner el resultado al final de la lista de parámetros. Si lo hace tantas veces como haya parámetros, ha transformado todos los parámetros y los ha vuelto a ordenar.Para la segunda parte del código, cambié su lógica para que sea menos confusa: el bucle externo itera sobre los parámetros y el bucle interno itera sobre los componentes de la ruta.
for x; do … done
itera sobre los parámetros posicionales, es un modismo conveniente. Utilizo una forma compatible con POSIX de hacer coincidir una cadena con un patrón: lacase
construcción.Probado con dash 0.5.5.1, pdksh 5.2.14, bash 3.2.39, bash 4.1.5, ksh 93s +, zsh 4.3.10.
Nota al margen: parece haber un error en bash 4.1.5 (no en 3.2): si el patrón del caso es
"${common_path%/}"/*
, una de las pruebas falla.bash, ksh
Si está en bash (o ksh), puede usar matrices; no entiendo por qué parece estar restringiéndose a los parámetros posicionales. Aquí hay una versión que usa una matriz. Tengo que admitir que no es particularmente más claro que la versión POSIX, pero evita la baraja inicial n ^ 2.
Para la parte de normalización de barra, utilizo la construcción de
${foo//PATTERN/REPLACEMENT}
construcción ksh93 para reemplazar todas las ocurrencias dePATTERN
in$foo
porREPLACEMENT
. El patrón es+(\/)
hacer coincidir una o más barras; bajo bash,shopt -s extglob
debe estar vigente (equivalentemente, comenzar bash conbash -O extglob
). La construcciónset ${!a[@]}
establece los parámetros posicionales en la lista de subíndices de la matriza
. Esto proporciona una forma conveniente de iterar sobre los elementos de la matriz.Para la segunda parte, utilizo la misma lógica de bucle que la versión POSIX. Esta vez, puedo usarlo
[[ … ]]
ya que todos los proyectiles apuntados aquí lo admiten.Probado con bash 3.2.39, bash 4.1.5, ksh 93s +.
zsh
Lamentablemente, zsh carece de la
${!array[@]}
función para ejecutar la versión ksh93 tal cual. Afortunadamente, zsh tiene dos características que hacen que la primera parte sea muy fácil. Puede indexar los parámetros posicionales como si fueran la@
matriz, por lo que no es necesario utilizar una matriz intermedia. Y zsh tiene una construcción de iteración de matriz :"${(@)array//PATTERN/REPLACEMENT}"
realiza el reemplazo de patrón en cada elemento de matriz a su vez y evalúa la matriz de resultados (de manera confusa, necesita las comillas dobles aunque el resultado sea varias palabras; esta es una generalización de"$@"
). La segunda parte es esencialmente sin cambios.Casos de prueba
Mis soluciones se prueban y comentan mínimamente. He cambiado la sintaxis de sus casos de prueba para analizar bajo shells que no tienen
$'…'
e informar fallas de una manera más conveniente.fuente
¿Por qué no usas solo $ 1, $ 2 .. $ 9, $ {10}, $ {11} .. y así sucesivamente? Es aún más SECO que lo que estás intentando hacer :)
Más sobre la relación entre $ number y $ @:
$ @ puede considerarse una forma abreviada de "todos los elementos de una matriz que contiene todos los argumentos"
Entonces, $ @ es una especie de taquigrafía de $ {args [@]} (args aquí es una matriz 'virtual' que contiene todos los argumentos, no una variable real, eso sí)
$ 1 es $ {args [1]}, $ 2 es $ {args [2]}, y así sucesivamente.
Cuando presione [9], use una llave: $ {10} es $ {args [10]}, $ {11} es $ {args [11]}, y así sucesivamente.
Use indirectamente un argumento de línea de comando
Ejemplo:
fuente
${args[$i]}
.Creo que lo que quieres es
shift
fuente
No sé exactamente por qué no solo usas $ 1 $ 2, etc., pero ... Esto puede satisfacer tus necesidades.
salida
set
funciona de todo lo que le sigue, para crear $ 1, $ 2 ... etc. Por supuesto, esto anulará los valores originales, así que tenga en cuenta eso.fuente
eval
algunos consideran que esevil
... (tal vez sea por la ortografía :) ... Sieval
es "malo", entonces $ {! Var} es igualmente "malo"? ... Para mí es solo una parte del lenguaje, y una parte útil, por cierto ... pero definitivamente prefiero $ {! Var} ...Tenga en cuenta que apoyo espacios en los nombres de archivo.
Agregué un caso de prueba para nombres de archivos con espacios y arreglé 2 pruebas que faltaban un /
fuente