Por que o printf ignora o IFS ao imprimir o resultado do meu script?

1

Esta é uma continuação de uma pergunta publicada no SO.

Eu escrevi um script chamado except , que deve imprimir todos os nomes de arquivos / diretórios, exceto os dados assim.

$ ls
a b c d
$ rm $(except b d)
$ ls
b d

O script que eu escrevi até agora parece com isso

shopt -s extglob
shopt -s nullglob

old_ifs=$IFS
IFS='|'
matches="!($*)"
IFS=' '

printf '%s' $matches
IFS=$old_ifs

Isso funciona mais ou menos, mas o principal problema é que o printf não parece respeitar o IFS definido como (em branco).

Apenas os imprime sem um espaço entre eles. Se eu usar o echo, ele funciona (exceto para a nova linha adicionada). Mas por razões de compatibilidade eu quero usar printf para esta tarefa. Como posso conseguir isso? O que estou fazendo errado?

Eu também tentei usar o modificador %q , que também não resultou na saída desejada.

printf '%q' $matches
    
por helpermethod 12.02.2013 / 11:06

1 resposta

3
$ ls
a b c d
$ rm $(except b d)
$ ls
b d

Isso não pode funcionar, pelo menos não de forma confiável, porque "except" não pode decidir como o shell irá dividir (e expandir ainda mais) sua saída antes de passá-lo para o comando rm .

Para responder à sua pergunta, o printf não usa $IFS . O único comando que usa o IFS é read . Além disso, o $ IFS é usado pelo shell para dividir palavras e unir os argumentos posicionais em "$*" .

Você provavelmente quer:

 printf '%s ' $matches

Ou

 printf '%s\n' $matches

Mas, novamente, em

 rm $(except a b)

O shell que interpreta essa linha de comando dividirá a saída de except de acordo com seu próprio $IFS (por espaço padrão, tabulação ou nova linha, é por isso que usar espaço ou \n acima não faz diferença) e também expandir os curingas para lá.

Portanto, se os arquivos diferentes de a e b forem "this file.txt" e **a** , except produzirá "this file.txt **a** " e você acabará tentando remover this , file.txt e a (pois **a** expandirá para todos os arquivos com a em seu nome).

Se você deseja unir as correspondências com espaços sem o espaço à direita, faça o seguinte:

IFS=
set -- $matches
IFS=' '
matches="$*"
    
por 12.02.2013 / 14:19