É possível consultar os índices em $@
? Não consigo encontrar nenhuma referência para usar como a seguir em qualquer lugar no wiki do GrayCat , e o Advanced Scripting Guide e outros atribuem isso a uma variável diferente antes de modificá-la.
$ echo ${@[0]}
-bash: ${@[0]}: bad substitution
O objetivo é SECO : O primeiro argumento é usado para uma coisa, e o restante para outra, e eu gostaria de evitar duplicar o código para normalizar, a $@
matriz ou criar uma função separada para isso (embora neste momento provavelmente é a saída mais fácil).
Esclarecimento: O objetivo era modificar os valores do comprimento variável $@
para facilitar a depuração do código . A versão atual é um pouco hacky para o meu gosto, embora funcione mesmo para caminhos bizarros como
$'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'
Atualização : parece que isso não é possível. O código agora usa duplicação de código e dados, mas pelo 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"
}
O Bounty é direcionado a qualquer pessoa que possa se livrar da duplicação de código para recolher barras duplicadas ou duplicação de dados para manter $1
e os outros parâmetros, ou ambos, mantendo o código em um tamanho razoável e sucedendo em todos os testes de unidade:
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
Respostas:
POSIX
Para normalizar as barras em todos os parâmetros, usarei o truque do argumento rotativo:
$1
desative, transforme-o e coloque o resultado no final da lista de parâmetros. Se você fizer isso quantas vezes houver parâmetros, você transformou todos os parâmetros e os colocou novamente em ordem.Na segunda parte do código, mudei sua lógica para menos confusa: o loop externo itera sobre os parâmetros e o loop interno itera sobre os componentes do caminho.
for x; do … done
itera sobre os parâmetros posicionais, é um idioma conveniente. Eu uso uma maneira compatível com POSIX de combinar uma string com um padrão: acase
construção.Testado com o traço 0.5.5.1, pdksh 5.2.14, bash 3.2.39, bash 4.1.5, ksh 93s +, zsh 4.3.10.
Nota: parece haver um bug em bash 4.1.5 (e não em 3.2): se o padrão caso é
"${common_path%/}"/*
, um dos testes falhar.bash, ksh
Se você está no bash (ou ksh), pode usar matrizes - não entendo por que você parece estar se restringindo aos parâmetros posicionais. Aqui está uma versão que usa uma matriz. Eu tenho que admitir que não é particularmente mais claro que a versão POSIX, mas evita o embaralhamento inicial n ^ 2.
Para a parte de normalização da barra, eu uso a construção de
${foo//PATTERN/REPLACEMENT}
construção ksh93 para substituir todas as ocorrências dePATTERN
in$foo
porREPLACEMENT
. O padrão é+(\/)
corresponder a uma ou mais barras; em bash,shopt -s extglob
deve estar em vigor (equivalentemente, inicie o bash combash -O extglob
). A construçãoset ${!a[@]}
define os parâmetros posicionais para a lista de subscritos da matriza
. Isso fornece uma maneira conveniente de iterar sobre os elementos da matriz.Para a segunda parte, tenho a mesma lógica de loop que a versão POSIX. Desta vez, eu posso usar,
[[ … ]]
já que todas as conchas direcionadas aqui o suportam.Testado com o bash 3.2.39, bash 4.1.5, ksh 93s +.
zsh
Infelizmente, o zsh não possui o
${!array[@]}
recurso para executar a versão ksh93 como está. Felizmente, o zsh tem dois recursos que facilitam a primeira parte. Você pode indexar os parâmetros posicionais como se fossem a@
matriz, portanto, não há necessidade de usar uma matriz intermediária. E o zsh tem uma construção de iteração de matriz :"${(@)array//PATTERN/REPLACEMENT}"
executa a substituição de padrão em cada elemento da matriz e avalia a matriz de resultados (confusamente, você precisa de aspas duplas, mesmo que o resultado seja várias palavras; isso é uma generalização de"$@"
). A segunda parte é essencialmente inalterada.Casos de teste
Minhas soluções são minimamente testadas e comentadas. Alterei a sintaxe dos seus casos de teste para analisar em shells que não possuem
$'…'
e reportar falhas de uma maneira mais conveniente.fonte
Por que você não usa apenas $ 1, $ 2 .. $ 9, $ {10}, $ {11} ... e assim por diante? É ainda mais SECO do que você está tentando fazer :)
Mais sobre a relação entre $ number e $ @:
$ @ pode ser considerado uma abreviação para "todos os elementos de uma matriz que contêm todos os argumentos"
Portanto, $ @ é uma forma abreviada de $ {args [@]} (args aqui é uma matriz 'virtual' contendo todos os argumentos - e não uma variável real, veja bem)
$ 1 é $ {args [1]}, $ 2 é $ {args [2]} e assim por diante.
Quando você clicar em [9], use uma chave: $ {10} é $ {args [10]}, $ {11} é $ {args [11]} e assim por diante.
Indiretamente, use um argumento de linha de comando
Exemplo:
fonte
${args[$i]}
.Eu acho que o que você quer é
shift
fonte
Eu não sei bem por que você não usa apenas $ 1 $ 2, etc. mas ... Isso pode atender às suas necessidades.
resultado
set
funciona de qualquer coisa que se segue, para criar $ 1, $ 2 .. etc. Isso obviamente substituirá os valores originais, portanto, esteja ciente disso.fonte
eval
é considerado, por alguns, comoevil
... (talvez seja por causa da ortografia :) ... Seeval
for "ruim", então $ {! Var} é igualmente "ruim"? ... Para mim, isso é apenas parte da linguagem, e uma parte útil, pelo que .. mas eu definitivamente prefiro $ ... {var!}Nota: Suporte espaços em nomes de arquivos.
Adicionei um caso de teste para nomes de arquivos com espaços e corrigi 2 testes que estavam faltando um líder /
fonte