Estou tentando entender esta linha a partir de um script de shell. Eu sei que isso $(..)
significa executar ..
e inserir sua saída onde você encontrar $()
em uma instrução. Mas o que está acontecendo entre esses parênteses? O que é o \ls
fazer e como isso se relaciona com o que está acontecendo \
nas linhas anteriores? Isso é uma \\
divisão em duas linhas? É \ls
o mesmo que normal ls
?
APPCLASSPATH=$CLASSPATH:$({ \
\ls -1 "$VOLTDB_VOLTDB"/voltdb-*.jar; \
\ls -1 "$VOLTDB_LIB"/*.jar; \
\ls -1 "$VOLTDB_LIB"/extension/*.jar; \
} 2> /dev/null | paste -sd ':' - )
Responder1
A saída dos 3 ls
comandos é passada para o paste
comando que os mescla no valor:
$VOLTDB_VOLTDB"/voltdb-*.jar:$VOLTDB_LIB"/*.jar:$VOLTDB_LIB"/extension/*.jar
OBSERVAÇÃO:As variáveis $VOLTDB_VOLTDB
e $VOLTDB_LIB
serão expandidas e poderá haver mais valores do que apenas um arquivo para cada um desses ls
comandos. Veja *
lá? Esse é um caractere glob que atua como curinga e se expande para qualquer coisa entre o lado esquerdo (voltdb-) e o lado direito (.jar), por exemplo.
Eles corresponderiam a:
voltdb-1.jar
voltdb-blah.jar
voltdb-12345.jar
Tudo é então incluído na variável APPCLASSPATH
:
APPCLASSPATH=$CLASSPATH:$VOLTDB_VOLTDB"/voltdb....etc.
O comando colar
Aqui está um exemplo em que estou usando o seq
comando para gerar uma sequência de números de 1 a 10.
$ seq 10 | paste -sd ':' -
1:2:3:4:5:6:7:8:9:10
Você pode ver que o paste
comando está mesclando a saída e separando-a com dois pontos ( :
).
Você também pode imitar o comando de exemplo assim:
$ { echo "hi1"; echo "hi2"; echo "hi3"; } | paste -sd ':' -
hi1:hi2:hi3
OBSERVAÇÃO:O -
comando to the paste diz para ele pegar a entrada do STDIN e imprimir cada argumento conforme ele chega, separado por a :
.
Com diferentes opções, paste
também é possível dividir os dados em grupos, com base no número de -
's depois deles.
Colar exemplos
Aqui está um exemplo com 2 -
's.
$ seq 10 | paste - -
1 2
3 4
5 6
7 8
9 10
Aqui estão 3 -
.
$ seq 10 | paste - - -
1 2 3
4 5 6
7 8 9
10
Portanto, está dizendo paste
quantos argumentos paste
devem ser impressos em cada linha. Mas não se confunda, o exemplo com o qual você está lidando é simplesmente pegar a entrada do STDIN, separar cada argumento em espaços e imprimi-lo seguido por a :
. Ao fornecer vários -
, você está dizendo paste
para receber argumentos, 2 de cada vez, 3 de cada vez, etc.
Argumentos 2 de cada vez, separados por :
's:
$ seq 10 | paste -d ':' - -
1:2
3:4
5:6
7:8
9:10
$ seq 10 | paste -d ':' - - -
1:2:3
4:5:6
7:8:9
10::
Aliás, se você incluir a -s
opção, estará dizendo paste
para levar os argumentos em série (em série). Veja o que acontece quando você o usa em um dos exemplos acima.
2 de cada vez:
$ seq 10 | paste -sd ':' - -
1:2:3:4:5:6:7:8:9:10
3 de cada vez:
$ seq 10 | paste -sd ':' - - -
1:2:3:4:5:6:7:8:9:10
Responder2
$(command)
executa um comando e substitui sua saída.
{ list; }
é um comando de grupo que executa vários comandos no ambiente shell atual. É semelhante a (list)
, mas não forma um subshell.
\command
é usado para ignorar aliases para comandos, o que pode alterar consideravelmente o comportamento esperado de um comando.
O \
no final da linha significa simplesmente que esta linha continua, então o shell verá a próxima linha como parte da atual. Geralmente não é necessário quando isso é óbvio no contexto (parênteses abertos ou citação).
Responder3
APPCLASSPATH=$CLASSPATH:$({ \ \ls -1 "$VOLTDB_VOLTDB"/voltdb-*.jar; \ \ls -1 "$VOLTDB_LIB"/*.jar; \ \ls -1 "$VOLTDB_LIB"/extension/*.jar; \ } 2> /dev/null | paste -sd ':' - )
\ls
é como ls
, exceto que se ls
for um alias, a barra invertida impede a expansão do alias. Isso garante que o ls
comando seja usado e não algum alias que possa adicionar saída indesejada, como um sufixo classificador ( -F
).
Os ls
comandos, chamados com nomes de arquivos existentes como argumentos, listam seus argumentos, um por linha. A opção -1
não tem efeito pois a saída de ls
vai para um tubo e não para um terminal. Se ls
receber um argumento que não seja o nome de um arquivo existente, ele não exibirá nada em sua saída padrão e, em vez disso, exibirá um erro. Erros dos ls
comandos são redirecionados para lugar nenhum pelo 2> /dev/null
. Há dois motivos pelos quais ls
pode receber um argumento que não é um arquivo: se uma das variáveis não se referir a um diretório legível existente ou se não houver nenhum arquivo que corresponda ao padrão curinga. Em ambos os casos, o padrão é passado sem expansão para ls
.
As barras invertidas no final das linhas fazem com que o shell ignore a nova linha a seguir. Nenhum deles é útil aqui, pois em cada ponto onde são usados, o shell espera uma nova linha opcional.
As chaves {…} agrupam os comandos. O comando composto { \ls …; \ls …; \ls … ; }
é canalizado paste
e tem seus erros redirecionados para /dev/null
.
O paste
comando une todas as linhas de entrada com um :
ponto intermediário. É equivalente a, tr '\n' :
exceto que não coloca um :
no final.
A substituição do comando $(…)
faz com que a saída de paste
seja interpolada em APPCLASSPATH
, após o valor da CLASSPATH
variável com dois pontos para separar as duas partes.
Aqui está uma versão simplificada. Isso é um pouco diferente do original porque, se nenhum dos padrões curinga corresponder a nada, APPCLASSPATH
será igual a CLASSPATH
sem dois pontos extras no final (o que provavelmente é desejável).
APPCLASSPATH=$CLASSPATH:$(
\ls "$VOLTDB_VOLTDB"/voltdb-*.jar "$VOLTDB_LIB"/*.jar "$VOLTDB_LIB"/extension/*.jar |
tr '\n' :) 2>/dev/null
APPCLASSPATH=${APPCLASSPATH%:}