Entenda a substituição de comandos complexos com {} e vários '\ ls'

5

Estou tentando entender essa linha de um script de shell. Eu sei que $(..) significa executar o .. e inserir sua saída onde você encontra $() em uma instrução. Mas o que está acontecendo entre esses parênteses? O que o \ls está fazendo e como isso se relaciona com o \ nas linhas anteriores? Isso é um \ dividido em duas linhas? O \ls é o mesmo que o 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 ':' - )
    
por bernie2436 10.10.2013 / 22:18

3 respostas

5

A saída dos comandos 3 ls é passada para o comando paste , que os mescla no valor:

$VOLTDB_VOLTDB"/voltdb-*.jar:$VOLTDB_LIB"/*.jar:$VOLTDB_LIB"/extension/*.jar

NOTA: As variáveis $VOLTDB_VOLTDB e $VOLTDB_LIB serão expandidas e pode haver mais valores do que apenas um arquivo para cada um desses comandos ls . Veja o * ai? Esse é um caractere glob que age como um caractere curinga e se expande para qualquer coisa entre o lado esquerdo (voltdb-) e o lado direito (.jar), por exemplo.

Estes corresponderiam:

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 comando seq para gerar uma sequência de números, 1-10.

$ seq 10 | paste -sd ':' -
1:2:3:4:5:6:7:8:9:10

Você pode ver que o comando paste está mesclando a saída e a separando 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 obter a entrada de STDIN e imprimir cada argumento conforme ele é enviado, separado por : .

Com diferentes opções para paste , também é possível dividir os dados em grupos, com base no número de - depois dela.

Colar exemplos

Veja um exemplo com 2 - 's.

$ seq 10 | paste - -
1       2
3       4
5       6
7       8
9       10

Aqui estão 3 - 's.

$ seq 10 | paste - - -
1       2       3
4       5       6
7       8       9
10

Então, 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 de STDIN, separar cada argumento em espaços e imprimi-lo seguido por um : . Ao dar vários - , você está dizendo paste para receber argumentos, 2 e uma vez, 3 de cada vez, etc.

Argumentos 2 por 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::

Por acaso, se você incluir a opção -s , estará dizendo paste para usar 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
    
por 10.10.2013 / 22:26
3

$(command) executa um comando e substitui sua saída.

{ list; } é um comando de grupo, executando vários comandos no ambiente atual do shell. É semelhante a (list) , mas não faz um subshell.

\command é usado para ignorar aliases para comandos, o que pode alterar consideravelmente o comportamento esperado dos comandos.

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êntese ou citação aberta).

    
por 10.10.2013 / 22:30
3
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 contrabarra impede a expansão de alias. Isso garante que o comando ls seja usado e não algum alias que possa adicionar saída indesejada, como um sufixo de classificador ( -F ).

Os comandos ls , 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 está indo para um pipe 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 exibirá um erro. Erros dos comandos ls são redirecionados para lugar nenhum por 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 correspondente ao padrão curinga. Em ambos os casos, o padrão é passado não expandido para ls .

As barras invertidas no final das linhas fazem com que o shell ignore a nova linha seguinte. Nenhum deles é útil aqui, pois em todos os pontos em que são usados, o shell espera uma nova linha opcional.

As chaves {…} agrupam os comandos. O comando composto { \ls …; \ls …; \ls … ; } é enviado para paste e tem seus erros redirecionados para /dev/null .

O comando paste une todas as linhas de entrada com : entre elas. É 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 variável CLASSPATH com dois-pontos para separar as duas partes.

Aqui está uma versão simplificada. Isso é um pouco diferente do original, pois, se nenhum dos padrões de caracteres curinga corresponder a nada, APPCLASSPATH será igual a CLASSPATH sem cólon posterior extra (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%:}
    
por 11.10.2013 / 03:03