isso é super trivial e eu encontrei muitas respostas próximas, mas ainda não consigo resolver isso. eu fiz um script com um argumento, basicamente algo como:
var1=$1
echo "outside the pipe, my variable is set: $var1"
ls *.* | xargs sh -c 'echo "$0" "$@"; echo "inside the pipe, my variable is empty: $var1"'
meu problema é que eu preciso canalizar uma lista de nomes de arquivos e também minha variável. Como eu faria isso? tentei escrever minha lista de arquivos em uma matriz, anexar/anular meu argumento e passá-lo para o pipe, mas isso cria problemas mais tarde, pois processo isso em pedaços, meu script original é algo como (imagemagick):
ls *.png | xargs -n 100 sh -c 'convert "$0" "$@" -evaluate-sequence $var1 ../out2/"$0"'
qualquer ajuda é muito apreciada!
Não, você não precisa canalizar uma lista de nomes de arquivos.
Ou seja, forneça o shell filho interno
$var1
como o primeiro argumento (o argumento zero deve ser o nome do shell).O shell interno
$var1
sai da lista de parâmetros e também faz o mesmo para o primeiro nome de caminhofind
encontrado (não sei por que, mas isso pelo menos o torna equivalente ao que acredito que seu código faz) e, em seguida, desloca esses de$@
usarshift 2
.Se você precisar fazer isso em lotes de exatamente 100:
A razão pela qual isso é mais seguro do que canalizar a saída
ls
é porque os nomes de caminho são passados como uma lista terminada por nulo em vez de uma lista terminada por nova linha. Osh
script é o mesmo em ambas as variações e usa$var1
como argumento de linha de comando.A razão pela qual seu código não funciona é porque o
sh -c
shell não conhece$var1
seu shell pai.Relacionado:
O
sh -c
é um novo shell, então você precisa fazer umexport
de$var1
para que os procs filhos o tenham ou o passemsh -c
como um argumento para ele.O outro problema com o seu exemplo é que você tem a variável dentro de ticks únicos.
Você realmente não precisa executar um outro shell para fazer isso. Para lidar com todos os arquivos correspondentes à expressão glob, basta usar o glob na linha de comando do programa que você deseja executar no final:
Se você precisar acessar apenas parte dos arquivos, armazene-os em um array e fatie ou indexe:
(
"${files[0]}"
é o primeiro nome de arquivo,"${files[@]:1}"
expande para todos os outros)A partir daí, podemos processar os arquivos cem por vez:
Ou seja, se eu interpretei seu
xargs
comando corretamente. Parece passar o primeiro nome do arquivo como o argumento zero parash -c
(geralmente como o nome do shell).Mas para responder à pergunta como você fez, você pode
export
usar a variável para torná-la visível para o shell interno ou colocá-la entre aspas duplas para expandi-la pelo shell externo. Por exemploou
Ambos saída
foo bar
. A passagem pelo ambiente é melhor porque a sintaxe é mais limpa (observe os diferentes tipos de aspas ao redor$var
e$1
no último), e quaisquer aspas no valor da variável não causarão problemas, como no segundo caso.