Você precisa usar "$(somecmd "$file")"
.
Sem as aspas, um caminho com um espaço será dividido no argumento para somecmd
e ele será direcionado para o arquivo errado. Então você precisa de citações no interior.
Quaisquer espaços na saída de somecmd
também causarão divisão, portanto, você precisará de cotações do lado de fora de toda a substituição de comandos.
As citações dentro da substituição do comando não têm efeito sobre as citações fora dele. O manual de referência do próprio Bash não é muito claro sobre isso, mas O BashGuide menciona isso explicitamente . O texto em POSIX também exige, como "qualquer script de shell válido" é permitido dentro de $(...)
:
With the
$(command)
form, all characters following the open parenthesis to the matching closing parenthesis constitute the command. Any valid shell script can be used for command, except a script consisting solely of redirections which produces unspecified results.
Exemplo:
$ file="./space here/foo"
a. Sem cotações, dirname
processa os dois ./space
e here/foo
:
$ printf "<%s>\n" $(dirname $file)
<.>
<here>
b. Citações dentro, dirname
processa ./space here/foo
, dando ./space here
, que é dividido em dois:
$ printf "<%s>\n" $(dirname "$file")
<./space>
<here>
c. Citações fora, dirname
processa ./space
e here/foo
, saídas em linhas separadas, mas agora as duas linhas formam um único argumento :
$ printf "<%s>\n" "$(dirname $file)"
<.
here>
d. Citações dentro e fora, isso dá a resposta correta:
$ printf "<%s>\n" "$(dirname "$file")"
<./space here>
(que possivelmente seria mais simples se dirname
processasse apenas o primeiro argumento, mas isso não mostrasse a diferença entre os casos a e c.)
Observe que, com dirname
(e possivelmente outros), você também precisa adicionar --
para impedir que o nome do arquivo seja usado como opção, caso comece com um traço, use "$(dirname -- "$file")"
.