Como obter o resultado de um comando grep em uma variável em outra variável

0

Estou listando os arquivos em um diretório que corresponda a um determinado critério. Uma das coisas que desejo fazer com cada arquivo no diretório é extrair sua data de 6 dígitos e colocá-la em uma variável. Meu script atualmente é assim:

for i in $(ls $INPUT_DIR | egrep -i '^'$INPUT_FILE_PREFIX'[0-9][0-9]([0][1-9]|1[0-2])([0][1-9]|[12][0-9]|[3][01])'$INPUT_FILE_SUFFIX); do   
 MYDATE=$("$i" | grep -oP '\d{6,6}')
 echo $MYDATE
done

O texto acima leva ao erro "somefile": command not found .

O que parece estranho para mim é que, se eu substituir MYDATE=$("$i" | grep -oP '\d{6,6}') por echo "$i" | grep -oP '\d{6,6}' , tudo funciona bem.

Como faço para que meu script passe "$i" como uma string em vez de um comando?

    
por paul frith 14.02.2018 / 15:44

5 respostas

3

Parece que você está tentando analisar um número de seis dígitos em nomes de arquivos que começam com $INPUT_FILE_PREFIX e terminam com $INPUT_FILE_SUFFIX .

Isso fará isso:

for name in "$INPUT_DIR/$INPUT_FILE_PREFIX"??????"$INPUT_FILE_SUFFIX"; do
    test -f "$name" || continue

    number=${name#$INPUT_DIR/$INPUT_FILE_PREFIX}
    number=${number%$INPUT_FILE_SUFFIX}

    printf "Number = %s\n" "$number"
done

Altere todos os ? para [0-9] se você quiser apenas coincidir os dígitos ( ? corresponde a um único caractere, independentemente do que esse caractere é).

As substituições de parâmetro no loop remove a primeira parte do valor de $name e, em seguida, a última parte da sequência restante, deixando o número (seis caracteres entre prefixo e sufixo) no meio como a única coisa restante a variável $number .

O comando

MYDATE=$("$i" | grep -oP '\d{6,6}')

, como você descobriu, será interpretado como invocando o que está em $i como um comando. Ao mesmo tempo, você disse que colocar echo na frente de "$i" faria com que funcionasse, o que faz:

MYDATE=$(echo "$i" | grep -oP '\d{6,6}')

Relacionado ao seu código: Por que * not * pars 'ls'?

    
por 14.02.2018 / 16:04
2

Eu recomendaria uma maneira um pouco diferente de percorrer os nomes dos arquivos usando o globbing estendido para reunir os nomes dos arquivos:

shopt -s extglob
for d in "${INPUT_DIR}"/"${INPUT_FILE_PREFIX}"[0-9][0-9]@(0[1-9]|1[0-9])@(0[1-9]|[12][0-9]|3[01])"${INPUT_FILE_SUFFIX}"
do 
  [[ $d =~ ${INPUT_FILE_PREFIX}([[:digit:]]+)${INPUT_FILE_SUFFIX} ]]
  MYDATE=${BASH_REMATCH[1]}
done

A sintaxe globbing é quase a mesma que a declaração grep que você tinha. Cada conjunto de @(...) apresenta uma solicitação para corresponder a qualquer um dos padrões fornecidos, que são separados por | . Percebi que o padrão (presumido dia) de [3] era uma classe de caractere único, então removi seus colchetes ao redor.

Quando tivermos os nomes de arquivos no loop for , você poderá usar o operador =~ da expressão condicional da expressão condicional de bash para remover os dígitos em MYDATE.

    
por 14.02.2018 / 16:12
1
for i in $(ls $INPUT_DIR | egrep -i '^'$INPUT_FILE_PREFIX'[0-9][0-9]([0][1-9]|1[0-2])([0][1-9]|[12][0-9]|[3][01])'$INPUT_FILE_SUFFIX);

Em geral, não há razão para usar ls em uma estrutura como essa, apenas torna o comando mais difícil de ler, além de você ter problemas com alguns casos de canto (veja ParsingLs no BashGuide ). No entanto, a regex que você possui não pode ser representada como uma shell glob padrão, portanto, há algum ponto em usá-la. Embora desde que isso tenha sido marcado com , podemos fazer isso no shell, ou com extglob (ou usando correspondências regex com a construção [[ .. ]] depois de um glob mais amplo).

shopt -s extglob
for i in "$INPUT_DIR/$INPUT_FILE_PREFIX"[0-9][0-9]@(0[1-9]|1[0-2])@(0[1-9]|[12][0-9]|3[01])"$INPUT_FILE_SUFFIX" ; do

Se você realmente não precisa de um padrão tão rígido, você pode usar apenas [0-9][0-9][0-9][0-9][0-9][0-9] .

Na atribuição para MYDATE , suponho que você queira apenas remover o prefixo e o sufixo. (embora se o seu prefixo / sufixo contiver uma string de seis dígitos, o grep também corresponderia a isso.)

MYDATE=${i#"$INPUT_DIR/"}              # remove the directory
MYDATE=${MYDATE#"$INPUT_FILE_PREFIX"}  # remove the prefix
MYDATE=${MYDATE%"$INPUT_FILE_SUFFIX"}  # and the suffix

Na íntegra:

shopt -s extglob
for i in "$INPUT_DIR/$INPUT_FILE_PREFIX"[0-9][0-9]@(0[1-9]|1[0-2])@(0[1-9]|[12][0-9]|3[01])"$INPUT_FILE_SUFFIX" ; do
    MYDATE=${i#"$INPUT_DIR/"}              # remove the directory
    MYDATE=${MYDATE#"$INPUT_FILE_PREFIX"}  # remove the prefix
    MYDATE=${MYDATE%"$INPUT_FILE_SUFFIX"}  # and the suffix
    echo "$MYDATE"
done
    
por 14.02.2018 / 16:11
0

Seu script está passando "$ i" como uma string, mas você está dizendo ao shell para usá-lo como um comando. A linha que diz

MYDATE=$("$i" | grep -oP '\d{6,6}')

está dizendo ao shell: "Expanda a variável i , então execute o comando resultante $ i, alimentando sua saída através do comando grep e atribua o resultado à variável MYDATE". O $(...) faz a mesma coisa que a construção double backtick que você usa com o comando echo "$i" | grep -oP '\d{6,6}' que faz o trabalho funcionar. Você simplesmente precisa do comando echo em um desses para obter os resultados desejados.

    
por 14.02.2018 / 15:51
0

Você já tentou substituição de processo bash ? Parece que isso tornaria o seu comando mais fácil e sem a necessidade de loops ou variáveis.

Basicamente, a substituição de processos não é bem conhecida, mas pode ser extremamente poderosa.

Process substitution feeds the output of a process (or processes) into the stdin of another process.

então, seu comando pode ser reduzido para algo assim:

grep -oP '\d{6,6}'<(egrep -i '^'$INPUT_FILE_PREFIX'[0-9][0-9]([0][1-9]|1[0-2])([0][1-9]|[12][0-9]|[3][01])'$INPUT_FILE_SUFFIX <(ls $INPUT_DIR))

A lógica por trás disso é melhor entendida com uma versão mais simples:

user@yrmv-191108:~/nums$ ls .
1  10  2  3  4  5  6  7  8  9
user@yrmv-191108:~/nums$ grep 1 <(ls .)
1
10
    
por 14.02.2018 / 17:45

Tags