Vi guias de script do Bash sugerindo o uso de matriz para trabalhar com nomes de arquivos que contenham espaço em branco. No entanto, o DashAsBinSh sugere que as matrizes não são portáveis, por isso estou procurando uma maneira compatível com POSIX de trabalhar com listas de nomes de arquivos que podem conter espaços em branco.
Eu estou olhando para modificar o script de exemplo abaixo para que ele echo
foo/target/a.jar
foo/target/b.jar
bar/target/lol whitespace.jar
Aqui está o script
#!/usr/bin/env sh
INPUT="foo/target/a.jar
foo/target/b.jar
bar/target/b.jar
bar/target/lol whitespace.jar"
# this would be produced by a 'ls' command
# We can execute the ls within the script, if it helps
dostuffwith() { echo $1; };
F_LOCATIONS=$INPUT
ALL_FILES=$(for f in $F_LOCATIONS; do echo `basename $f`; done)
ALL_FILES=$(echo "$ALL_FILES" | sort | uniq)
for f in $ALL_FILES
do
fpath=$(echo "$F_LOCATIONS" | grep -m1 $f)
dostuffwith $fpath
done
shell-script
filenames
quoting
posix
whitespace
Eero Aaltonen
fonte
fonte
Respostas:
Escudos POSIX têm uma matriz: os parâmetros de posição (
$1
,$2
, etc., colectivamente referidos como"$@"
).Isso é inconveniente porque existe apenas um e destrói qualquer outro uso dos parâmetros posicionais. Os parâmetros posicionais são locais para uma função, que às vezes é uma bênção e às vezes uma maldição.
Se for garantido que seus nomes de arquivo não contenham novas linhas, você poderá usar novas linhas como separador. Ao expandir a variável, primeiro desative o globbing
set -f
e defina a lista de caracteres de divisão de campoIFS
para conter apenas uma nova linha.Com os itens da sua lista separados por novas linhas, você pode usar muitos comandos de processamento de texto de maneira útil, em particular
sort
.Lembre-se de sempre colocar aspas duplas em torno das substituições de variáveis, exceto quando você desejar explicitamente que a divisão de campos ocorra (além de globbing, a menos que você tenha desativado).
fonte
sort | uniq
etapa original funcione conforme o esperado.Como sua
$INPUT
variável usa novas linhas como separadores, vou assumir que seus arquivos não terão novas linhas nos nomes. Como tal, sim, existe uma maneira simples de iterar sobre os arquivos e preservar o espaço em branco.A idéia é usar o
read
shell embutido. Normalmenteread
será dividido em qualquer espaço em branco e, portanto, os espaços serão divididos. Mas você pode definirIFS=$'\n'
e, em vez disso, será dividido apenas em novas linhas. Assim, você pode percorrer cada linha da sua lista.Aqui está a menor solução que eu poderia encontrar:
Basicamente, ele envia "$ INPUT" para o
awk
qual as deduplicadas são baseadas no nome do arquivo (ele se divide/
e depois imprime a linha se o último item não tiver sido visto antes). Então, uma vez que o awk tenha gerado a lista de caminhos de arquivo, usamoswhile read
para percorrer a lista.fonte
while
loop e, portanto,dostuffwith
é executado em um subshell. Portanto, quaisquer variáveis ou alterações feitas no shell em execução serão perdidas quando o loop for concluído. A única alternativa é usar um heredoc completo, o que não é tão desagradável, mas achei que seria preferível.IFS="\n"
divide em barra invertida e n caracteres. Masread file
, não há divisão.IFS="\n"
ainda é útil, pois remove os caracteres em branco do $ IFS que, de outra forma, teriam sido removidos no início e no final da entrada. Para ler uma linha, a sintaxe canônica é (IFS= read -r line
embora nada contenha espaços em branco) também funcionará.IFS=anything read -r line