Como iterar através de uma lista separada por vírgulas e executar um comando para cada entrada

4

Recebi um comando que gera uma lista separada por vírgula para tarefas autosys na variável $all_jobs :

box=box-of-jobs;all_jobs=$(jobscout -box $box | egrep "^\w+" | tr '\n' ','  | sed s/.$//); 

Eu quero chamar um comando sendevent para cada item na lista:

sendevent -verbose -S NYT -E JOB_OFF_HOLD -J $job --owner me

Então, por exemplo, se $all_jobs avaliou job1, job2, job3

Eu quero ligar

sendevent -verbose -S NYT -E JOB_OFF_HOLD -J job3 --owner me
sendevent -verbose -S NYT -E JOB_OFF_HOLD -J job2 --owner me
sendevent -verbose -S NYT -E JOB_OFF_HOLD -J job1 --owner me

Eu tenho certeza que eu poderia escrever um script ksh para passar, mas eu sei que essas coisas podem ser escritas muito mais rápido usando o awk / sed, ambos com os quais eu não estou muito familiarizado, então está além das minhas habilidades. Estou usando o ksh (em vez de bsh).

    
por Ian 06.02.2013 / 12:32

3 respostas

3

Se tiver certeza de que os campos entre as vírgulas não contêm espaços em branco, você pode fazer algo assim:

for job in $(echo $all_jobs | tr "," " "); do
    sendevent -verbose -S NYT -E JOB_OFF_HOLD -J "$job" --owner me
done

Se você precisar de algo mais robusto, dê uma olhada em as ferramentas necessárias para lidar com arquivos CSV sob o Unix .

    
por 06.02.2013 / 14:21
6

A divisão de uma string em um caractere específico é incorporada ao shell em um nível muito profundo: se você escreve $var sem nenhuma aspas ao redor, ela é expandida da seguinte forma:

  1. Pegue o valor da variável var .
  2. Divida esse valor em uma lista de campos. O separador de campo é qualquer caractere no valor da variável IFS . Se IFS contiver caracteres de espaço em branco, os separadores consecutivos serão considerados como um; para caracteres que não são espaços em branco, os separadores consecutivos resultam em campos vazios.
  3. Execute globbing, ou seja, interprete cada campo resultante como um padrão curinga de nome de arquivo. Para cada padrão que corresponda a um ou mais arquivos, substitua-o pela lista de arquivos correspondentes.

O mesmo acontece com uma substituição de comando $(somecommand) , exceto que a etapa 1 é “coletar a saída da execução de somecommand e retirar todas as novas linhas no final”.

Para evitar toda essa ladainha e apenas obter o valor exato da variável, ou a saída do comando menos as novas linhas finais, certifique-se de colocar a substituição de variável ou substituição de comando entre aspas duplas: "$foo" , "$(foo)" .

Para dividir o resultado de uma substituição de comando em caracteres de vírgula, defina IFS=, e deixe a substituição desprotegida. Você precisa fazer mais uma coisa: desligue o globbing, com set -f (e restaure-o depois com set +f .

all_jobs=$(…)
set -f; IFS=,
for job in $all_jobs; do
  sendevent -verbose -S NYT -E JOB_OFF_HOLD -J "$job" --owner me
done
set =f; unset IFS
    
por 07.02.2013 / 02:40
0

Você pode usar xargs :

all_jobs="job1,job2,job3"
echo $all_jobs | tr '\n' ' ' | xargs -d, --replace=xx sendevent -verbose -S NYT -E JOB_OFF_HOLD -J xx --owner me

O canal através de tr pode não ser necessário se $all_jobs não tiver uma nova linha no final

    
por 06.02.2013 / 15:34