Tenho uma sequência de texto e espaços que se parece com isso:
macOS windows arch-linux ubuntu_linux
Quero anexar cada item (com espaços em branco indicando uma quebra entre eles) a um array bash. Como faço isso?
Tenho uma sequência de texto e espaços que se parece com isso:
macOS windows arch-linux ubuntu_linux
Quero anexar cada item (com espaços em branco indicando uma quebra entre eles) a um array bash. Como faço isso?
Se fizermos:
VAR=100:200:300:400
Nós podemos fazer:
echo ${VAR%%:*}
100
e
echo ${VAR##*:}
400
Existe algum equivalente que eu possa usar para obter os valores de 200 e 300?
Por exemplo, uma maneira de obter apenas o que está entre o segundo e o terceiro dois pontos, especificamente no caso de haver mais de três dois pontos?
Eu sei que o bash se esforça muito para manter as novas versões compatíveis com as anteriores.
No entanto, eles às vezes introduziram mudanças (pequenas, mas ainda assim) drásticas:
por exemplo quando não podíamos mais ter : { foo }
# que agora trava
mas em vez disso tinha que ter: { foo ;}
# ou seja, ter um ;
ou uma nova linha antes do fechamento}
(não tenho certeza de qual versão introduziu isso, foi há mais de 20 anos ^^)
Minha pergunta é: como descobrir quais outras mudanças "importantes" ocorreram ao longo de todo o histórico de atualizações do bash?
Talvez eu esteja perdendo, mas não encontro documentação que mostre que isso cd ''
deveria funcionar. Como não há um diretório com o nome ''
, parece óbvio que deveria falhar. Por exemplo,
mydir=
cd -- "$mydir" || exit 1 # succeeds!!
echo wrong
Parece um bug em cerca de um milhão de scripts, só esperando para acontecer. Será que isso é algum tipo de bug de compatibilidade com versões anteriores? Eu realmente preciso fazer uma verificação separada para um nome de variável vazio toda vez que eu cd
? Aliás, shellcheck
também não detecta isso.
Há uma resposta do SuperUser , que renomeia nomes de arquivos que contêm espaços em branco:
for f in *\ *; do mv "$f" "${f// /_}"; done
A parte que não entendo é *\ *
.
O autor escreveu que:
*\ *
Seleciona todos os arquivos com um espaço no nome como entrada para o loop for. O padrão X seleciona todos os arquivos com X no nome e, para o caractere especial espaço, precisamos usar uma barra para que o bash não o trate como uma separação de argumentos.
Já que *
não corresponde a um espaço, por que *\ *
também corresponde a arquivos com vários caracteres de espaço quando ele só tem um espaço?
Tenho minha própria implementação de um servidor Redis que gostaria de testar por meio de um script de shell.
A ideia geral é alimentá-lo com alguns comandos por meio de nc
, e como nc
imprime a saída do meu programa (resposta) para stdout
, capturar a resposta em uma variável de script e compará-la com a saída esperada.
Não consegui fazê-lo funcionar e não sei qual é o problema e como resolvê-lo.
Esta é uma parte do roteiro:
#!/bin/bash
set -eu
PORT=6380;
RUST_LOG=info ./run.sh --port $PORT 2>/dev/null & sleep 1; # Give it some time to start.
i=0;
i=$((i+1)); printf 'Running test #%d...' "$i";
response=$(printf "*1\r\n\$4\r\nPING\r\n" | nc localhost $PORT);
if [ "$response" = '+PONG\r\n' ]; then
printf ' PASSED'
else
printf ' FAILED\nGot:\n%s\n\n' "$response"
fi;
sleep 0.1;
pkill redis-server;
Este é apenas um exemplo de teste. Quando um usuário envia o PING
comando, a resposta esperada é PONG
, mas ela é codificada e enviada de volta como +PONG\r\n
.
A saída CLI deste teste ( $ ./test.sh
) é:
Running test #1... FAILED
Got:
+PONG
Então, parece que a variável $response
realmente contém o que deveria.
Tentei remover +
, \r
, \n
, \r\n
da saída de referência sem sucesso, só para ver se isso ajudaria.
Terei testes mais complicados que incluem um caractere que precisa ser escapado ( $
), como \$5\r\nHello
, na resposta.
A propósito, a configuração manual response
funciona conforme o esperado.
response='+PONG\r\n';
if [ "$response" = '+PONG\r\n' ]; then
echo Equal
else
echo Different
fi;
Isto imprime Equal
, como esperado.
Depois de adicionar a saída de depuração por meio de set -ex
, posso ver que $response
armazena +PONG\r
, ou seja, sem \n
.
Running test #1...++ printf '*1\r\n$4\r\nPING\r\n'
++ nc localhost 6380
+ response=$'+PONG\r'
+ '[' $'+PONG\r' = '+PONG\r\n' ']'
+ printf ' FAILED\nGot:\n%s\n\n' $'+PONG\r'
FAILED
Got:
+PONG
Certo, então definir a saída de referência +PONG\r
deve funcionar, certo?
Running test #1...++ printf '*1\r\n$4\r\nPING\r\n'
++ nc localhost 6380
+ response=$'+PONG\r'
+ '[' $'+PONG\r' = '+PONG\r' ']'
+ printf ' FAILED\nGot:\n%s\n\n' $'+PONG\r'
FAILED
Got:
+PONG
Claramente não.
Tentei encapsular response
em {}
, assim: if [ "${response}" = '+PONG\r' ]; then
, sem sucesso.
O que estou perdendo?
Também estou curioso para saber como e por que \n
me perdi.
Estou executando-o zsh
em um Mac, se isso for mencionado, mas o comando diz claramente para usar bash
.
Se eu executar ps -p $$
o script de teste, obtenho 51547 ttys003 0:00.02 /bin/bash ./test.sh
.
Vamos definir uma função shell (aqui o shell é Bash) e testá-la
$ s () { xterm -e sleep 5 & }
$ s
[1] 307926
$
[1]+ Done xterm -e sleep 5
$
Com meu significado específico de melhor , posso redefinir s
assim
$ s () { xterm -e sleep 5 & disown ; }
$ s
[1] 307932
$
$
(nenhuma mensagem do shell quando o trabalho estiver concluído).
Aqui eu tenho que perguntar, é possível definir s
para que eu tenha
$ s () { pre_magic xterm -e sleep 5 post_magic ; }
$ s
$
$
ou seja, suprimir as informações do trabalho impressas no terminal pelo shell?
Um comando bash:
$(System.DefaultWorkingDirectory)/yq_linux_amd64 '. *= load("${{ parameters.HELM_CHART_PATH }}/values/DEV/${{ parameters.COMPONENT }}.yaml")' ${{ parameters.HELM_CHART_PATH }}/values/global-values.yaml > $(System.DefaultWorkingDirectory)/deployment-values.yaml
Está mesclando valores de 2 arquivos YAML e enviando a saída mesclada para um único arquivo. Não consigo entender a sintaxe da primeira aspa simples até que a saída seja redirecionada. Alguém pode me ajudar a entender o que isso significa?
Por que ambos os operandos estão depois do operador *=
? , que .
é o diretório atual, mas o que significa antes de *=
?
Além disso, por que apenas o 1º operando está entre load ()
e qual é o seu significado?
Qual é a maneira padrão, no bash, de verificar se uma variável de ambiente está configurada? Estou um pouco confuso entre as seguintes opções:
! [ -z "${VAR}" ]
[ -n "${VAR}" ]
[ "${VAR}" ]
Ou existe uma abordagem melhor?
Tenho um BASH
pipeline que em determinado momento executa um Singularity
contêiner com singularity exec da seguinte maneira:
singularity exec --bind `pwd`:/folder --bind $d:/results <image>.sif <tool_command> -i /folder/<file>.fastq -v /results/<output>/<file>.vcf -r /folder/<reference>.fna -s <vcf_sample_name> -j 24 -t 24 -o /results/<output_file_suffix>
Como estou executando vários experimentos ao mesmo tempo com uma matriz, estou redefinindo os experimentos com uma variável de ambiente que desejo adicionar ao <output_file_suffix>
; funciona para todas as etapas do pipeline, mas Singularity
parece que não consegue ver a(s) variável(is) que estou definindo no meu script...
Alguém tem alguma dica de como fazer isso? Pesquisei um pouco, mas --env
parece que não está funcionando. Agradeço desde já!