Bash Scripting e cotação

1

Estou lendo alguns livros sobre scripts bash e lutando para entender a cotação correta e o uso de IFS . Talvez alguém possa me ajudar com um pequeno exemplo envolvendo nomes de arquivos com aspas. Fazendo isso a partir de uma linha de comando, isso funciona para imprimir os nomes de arquivos corretamente, mesmo que incluam espaços:

set - *
for i in "$@"; do echo $i; done

Isso não funciona, pois quebra em espaços:

set - 'find . -name "*"'
for i in "$@"; do echo $i; done

Nem:

IFS=$'
IFS=$'\n' for i in 'find . -name "*" -type f'; do echo $i; done 
' set - 'find . -name "*" -print0' for i in "$@"; do echo $i; done

Nem a combinação que usa IFS=$'\n' e -print . Por que tudo isso falha?

O seguinte também falha, mas, neste caso, ele comete erros ("bash: erro de sintaxe próximo ao token inesperado 'do'"). Por quê?

IFS=$'\n'; for i in 'find . -name "*" -type f'; do echo $i; done 

mas isso funciona (observe o ";"):

IFS=''; for i in 'find . -name "*" -type f -print0'; do echo -e "$i\n"; done

e isso falha porque os nomes dos arquivos não são divididos (o for faz um loop apenas uma vez):

set - *
for i in "$@"; do echo $i; done

Então, novamente, por que o primeiro e o terceiro falharam?

Por fim, estou correto em minha opinião de que, ao definir IFS , '' é o mesmo que $'$'\n'' ? (Eu tentei ambos nesse exemplo imediatamente anterior.) Em caso afirmativo, por que eu aparentemente preciso de \n em vez de apenas %code% ?

* Bash é a versão 4.3.42 (1) no Ubuntu Gnome 16.04.

    
por Diagon 21.06.2016 / 11:18

1 resposta

0

Duas coisas que aprendi ao depurar comandos bash: Um) Se não estiver funcionando como você acha que deveria, faça o echo / printf dos comandos para garantir que eles exibam o que você acha que deveria. Dois) Execute manualmente os comandos que você tem dentro de seus comandos para ver se eles são executados corretamente (a menos que sejam comandos potencialmente destrutivos, como: rm, dd, chmod 777, etc.).

Como ou o que exatamente você está tentando realizar? O meu parece funcionar bem com esse comando na íntegra, então você precisa explicar o que você quer fazer. Você tem espaços em seus nomes de arquivos que estão causando problemas com seu comando? Contanto que você se livre do espaço da variável IFS, provavelmente funcionará do jeito que você deseja: IFS=$'\n\t' . A opção -print0 basicamente retira todos os separadores de linha, então tudo o que você quer desses comandos não tem nenhum separador, a menos que os arquivos tenham espaços em seus nomes. Para o seu segundo conjunto de perguntas:

IFS=$'\n' for i in 'find . -name "*" -type f'; do echo $i; done 

Este comando não funciona corretamente porque o bash o lê assim:

IFS=$'\n' for i in 'find . -name "*" -type f'
do echo $i
done

A primeira linha define o IFS para: $'\n' for i in . Depois disso, a próxima linha será lida como: do echo $i , o que não funciona, pois o comando do requer que um loop de alguma espécie seja o comando anterior. O próximo funciona porque o ponto-e-vírgula diz ao bash que o fim do comando foi atingido, então:

IFS=$'\n'
for i in 'find . -name "*" -type f'
do echo $i
done 

Finally, am I correct in my belief that when setting IFS, '' is the same as $'%bl0ck_qu0te%'? (I tried both in that immediately previous example.) If so, why do I apparently need $'\n' rather than just \n?

Sim para a primeira parte, '' e '$''' são considerados NULL, então são basicamente os mesmos. Isso ocorre porque interpreta %code% como uma string ANSI C. E você precisa ter aspas ao redor do \ n para ter o bash interpretando-o como uma string C para que um caractere de nova linha seja colocado no IFS.
Você pode ler mais sobre estes aqui .

    
por 21.06.2016 / 12:56