Dado um nome de arquivo no formulário someletters_12345_moreleters.ext
, quero extrair os 5 dígitos e colocá-los em uma variável.
Então, para enfatizar o ponto, eu tenho um nome de arquivo com um número x de caracteres e, em seguida, uma sequência de cinco dígitos cercada por um único sublinhado de cada lado e outro conjunto de x números de caracteres. Quero pegar o número de 5 dígitos e colocá-lo em uma variável.
Estou muito interessado no número de maneiras diferentes pelas quais isso pode ser realizado.
abc_12345_def_67890_ghi_def
é uma entrada válida. O que você quer que aconteça? Vamos supor que haja apenas uma sequência de 5 dígitos. Você ainda temabc_def_12345_ghi_jkl
ou1234567_12345_1234567
ou12345d_12345_12345e
como entrada válida com base na sua definição de entrada e a maioria das respostas abaixo não irá lidar com isso._
delimitador, entrada que contém a cadeia de destino apenas uma vez etc.). A melhor (mais genérica e mais rápida) resposta tem, após 10 anos, apenas 7 votos positivos, enquanto outras respostas limitadas têm centenas. Me faz perder a fé em desenvolvedores 😞Respostas:
Usar corte :
Mais genérico:
fonte
echo
, a menos que tenha certeza de que as variáveis não podem conter espaços em branco irregulares ou metacaracteres de shell. Veja mais stackoverflow.com/questions/10067266/…Se x for constante, a seguinte expansão de parâmetro executa a extração de substring:
onde 12 é o deslocamento (baseado em zero) e 5 é o comprimento
Se os sublinhados ao redor dos dígitos forem os únicos na entrada, você poderá remover o prefixo e o sufixo (respectivamente) em duas etapas:
Se houver outros sublinhados, provavelmente é possível de qualquer maneira, embora mais complicado. Se alguém souber executar as duas expansões em uma única expressão, eu também gostaria de saber.
Ambas as soluções apresentadas são pura purificação, sem a geração de processos envolvidos e, portanto, muito rápido.
fonte
bash: ${${a#*_}%_*}: bad substitution
no meu GNU bash 4.2.45.sh
script, o que provavelmente foi arriscado. Neste ponto, não consigo mais fazê-lo funcionar.:-
substituição "Usar valores padrão". Portanto,${a: -12:5}
produz os 5 caracteres 12 caracteres do final e${a: -12:-5}
os 7 caracteres entre o final 12 e o final 5.Solução genérica em que o número pode estar em qualquer lugar do nome do arquivo, usando a primeira dessas seqüências:
Outra solução para extrair exatamente uma parte de uma variável:
Se seu nome de arquivo sempre tiver o formato,
stuff_digits_...
você pode usar o awk:Outra solução para remover tudo, exceto dígitos, use
fonte
apenas tente usar
cut -c startIndx-stopIndx
fonte
startIndx-$((lastIndx-1))
start=5;stop=9; echo "the rain in spain" | cut -c $start-$(($stop-1))
git log --oneline | head -1 | cut -c 9-(end -1)
line=
git log --online | head -1` && echo $ line | cut -c 9 - $ (($ {# line} -1)) `mas neste caso em particular, pode ser melhor usar sed comogit log --oneline | head -1 | sed -e 's/^[a-z0-9]* //g'
Caso alguém queira informações mais rigorosas, você também pode pesquisá-las no man bash como este
Resultado:
fonte
${var: -4}
Aqui está como eu faria isso:
Explicação:
Específico do Bash:
[[ ]]
indica uma expressão condicional=~
indica que a condição é uma expressão regular&&
encadeia os comandos se o comando anterior foi bem-sucedidoExpressões regulares (RE):
_([[:digit:]]{5})_
_
são literais para demarcar / ancorar os limites correspondentes para a sequência que está sendo correspondida()
criar um grupo de captura[[:digit:]]
é uma classe de personagem, acho que fala por si{5}
significa exatamente cinco caracteres anteriores, classe (como neste exemplo) ou grupo deve corresponderEm inglês, você pode pensar assim: a
FN
sequência é iterada caractere por caractere até vermos um_
ponto em que o grupo de captura é aberto e tentamos corresponder cinco dígitos. Se essa correspondência for bem-sucedida nesse ponto, o grupo de captura salvará os cinco dígitos atravessados. Se o próximo caractere for um_
, a condição for bem-sucedida, o grupo de captura será disponibilizadoBASH_REMATCH
e a próximaNUM=
instrução poderá ser executada. Se alguma parte da correspondência falhar, os detalhes salvos serão descartados e o processamento de caractere por caractere continuará após o_
. por exemplo, seFN
onde_1 _12 _123 _1234 _12345_
, haveria quatro partidas falsas antes de encontrar uma correspondência.fonte
cut
). Também não depende da execução de um comando externo.Estou surpreso que essa solução pura do bash não tenha surgido:
Você provavelmente deseja redefinir o IFS para qual valor era antes ou
unset IFS
depois!fonte
IFS
parâmetros e posicionais:IFS=_ read -r _ digs _ <<< "$a"; echo "$digs"
Com base na resposta de jor (que não funciona para mim):
fonte
cut
é?Seguindo os requisitos
Eu encontrei algumas
grep
maneiras que podem ser úteis:ou melhor
E então com
-Po
sintaxe:Ou se você deseja ajustá-lo exatamente a 5 caracteres:
Finalmente, para armazená-lo em uma variável, basta usar a
var=$(command)
sintaxe.fonte
Invocation as 'egrep' is deprecated; use 'grep -E' instead
. Eu editei sua resposta.Se focarmos no conceito de:
"Uma sequência de (um ou vários) dígitos"
Poderíamos usar várias ferramentas externas para extrair os números.
Poderíamos facilmente apagar todos os outros caracteres, sed ou tr:
Mas se $ name contiver várias execuções de números, o acima irá falhar:
Se "name = someletters_12345_moreleters_323_end.ext", então:
Precisamos usar expressões regulares (regex).
Para selecionar apenas a primeira execução (12345 e não 323) no sed e perl:
Mas também poderíamos fazê-lo diretamente no bash (1) :
Isso nos permite extrair a PRIMEIRA execução de dígitos de qualquer tamanho,
cercados por qualquer outro texto / caracteres.
Nota :
regex=[^0-9]*([0-9]{5,5}).*$;
corresponderá exatamente a 5 dígitos. :-)(1) : mais rápido do que chamar uma ferramenta externa para cada texto curto. Não é mais rápido do que todo o processamento no sed ou awk para arquivos grandes.
fonte
Sem nenhum subprocesso, você pode:
Uma variante muito pequena disso também funcionará no ksh93.
fonte
Aqui está uma solução de prefixo-sufixo (semelhante às soluções fornecidas por JB e Darron) que corresponde ao primeiro bloco de dígitos e não depende dos sublinhados circundantes:
fonte
Adoro
sed
a capacidade de lidar com grupos regex:A opção um pouco mais geral seria não assumir que você tem um sublinhado
_
marcando o início da sua seqüência de dígitos, portanto, por exemplo, tirando todos os não-números que você começa antes de sua seqüência:s/[^0-9]\+\([0-9]\+\).*/\1/p
.Mais sobre isso, caso você não esteja muito confiante com os regexps:
s
é para _s_ubstitute[0-9]+
corresponde a mais de 1 dígito\1
links para o grupo n.1 da saída regex (o grupo 0 é a correspondência inteira, o grupo 1 é a correspondência entre parênteses neste caso)p
flag é para _p_rintingTodas as fugas
\
existem para fazersed
o processamento de regexp funcionar.fonte
Minha resposta terá mais controle sobre o que você deseja da sua string. Aqui está o código de como você pode extrair
12345
sua stringIsso será mais eficiente se você quiser extrair algo que tenha caracteres como
abc
ou caracteres especiais como_
ou-
. Por exemplo: Se sua string for assim e você desejar tudo o que é posteriorsomeletters_
e anterior_moreleters.ext
:Com o meu código, você pode mencionar exatamente o que deseja. Explicação:
#*
Ele removerá a string anterior, incluindo a chave correspondente. Aqui, a chave que mencionamos é_
%
Ela removerá a seguinte string, incluindo a chave correspondente. Aqui a chave que mencionamos é '_mais *'Faça algumas experiências você mesmo e você achará isso interessante.
fonte
Dado test.txt é um arquivo que contém "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
fonte
Ok, aqui vai pura Substituição de Parâmetro com uma string vazia. A ressalva é que defini someletters e moreletters como apenas caracteres. Se eles são alfanuméricos, isso não funcionará como está.
fonte
semelhante ao substr ('abcdefg', 2-1, 3) no php:
fonte
Há também o comando 'expr' do bash:
fonte
expr
não é um builtin.=~
operador suportado por[[
.Um pouco tarde, mas acabei de encontrar este problema e encontrei o seguinte:
Usei-o para obter resolução de milissegundos em um sistema incorporado que não possui% N para a data:
fonte
Uma solução bash:
Isso derruba uma variável chamada
x
. O varx
pode ser alterado para o var_
.fonte
Final Inklusive, semelhante às implementações JS e Java. Remova +1 se você não desejar isso.
Exemplo:
Mais exemplos de chamadas:
Você é bem vindo.
fonte