mv1 *.pngprimeiro expande o padrão curinga *.pngna lista de nomes de arquivos correspondentes e, em seguida, passa essa lista de nomes de arquivos para a função.
Então, dentro da função $1significa: pegue o primeiro argumento para a função, divida-o onde ele contém espaços em branco e substitua qualquer uma das partes separadas por espaços em branco que contenham caracteres curinga e correspondam a pelo menos um nome de arquivo pela lista de nomes de arquivo correspondentes. Parece complicado? É, e esse comportamento é útil apenas ocasionalmente e muitas vezes é problemático. Esse comportamento de divisão e correspondência ocorre apenas se $1ocorrer fora das aspas duplas, portanto, a correção é fácil: use aspas duplas. Sempre coloque aspas duplas nas substituições de variáveis, a menos que você tenha um bom motivo para não fazê-lo.
Por exemplo, se o diretório atual contiver os dois arquivos A* algorithm.pngegraph1.png , então mv1 *.pngpassa A* algorithm.pngcomo o primeiro argumento para a função e graph1.pngcomo o segundo argumento. Então $1é dividido em A*e algorithm.png. O padrão A*corresponde a A* algorithm.pnge algorithm.pngnão contém caracteres curinga. Assim, a função acaba sendo executada com mvos argumentos -n, A* algorithm.png, algorithm.pnge . Se você corrigir a função paratargetdir-v
então ele irá mover corretamente o primeiro arquivo.
Para processar todos os argumentos, diga ao shell para processar todos os argumentos e não apenas o primeiro. Você pode usar "$@"para significar a lista completa de argumentos passados para a função.
Isso está quase correto, mas ainda falha se um nome de arquivo começar com o caractere -, porque mvtratará esse argumento como uma opção. Passe --para mvdizer “não há mais opções após este ponto”. Esta é uma convenção muito comum que a maioria dos comandos suporta.
Um problema remanescente é que, se mvfalhar, esta função retorna um status de sucesso, porque o status de saída dos comandos no lado esquerdo de um pipe é ignorado. No bash (ou ksh), você pode usar set -o pipefailpara fazer o pipeline falhar. Observe que definir essa opção pode fazer com que outro código em execução no mesmo shell falhe, portanto, você deve configurá-lo localmente na função, o que é possível desde o bash 4.4.
function mv1 {
local -
set -o pipefail
mv -n -v -- "$@" "targetdir" | wc -l
}
Em versões anteriores, a configuração pipefailseria frágil, portanto, seria melhor verificar PIPESTATUSexplicitamente.
Ao interagir com funções, o Terminal Linux não passa o asterisco diretamente para o comando, mas seleciona o primeiro parâmetro correspondente e o passa para o comando.
Para permitir que o asterisco passe diretamente, é necessário escapar do asterisco usando uma barra invertida.
mv1 *.png
primeiro expande o padrão curinga*.png
na lista de nomes de arquivos correspondentes e, em seguida, passa essa lista de nomes de arquivos para a função.Então, dentro da função
$1
significa: pegue o primeiro argumento para a função, divida-o onde ele contém espaços em branco e substitua qualquer uma das partes separadas por espaços em branco que contenham caracteres curinga e correspondam a pelo menos um nome de arquivo pela lista de nomes de arquivo correspondentes. Parece complicado? É, e esse comportamento é útil apenas ocasionalmente e muitas vezes é problemático. Esse comportamento de divisão e correspondência ocorre apenas se$1
ocorrer fora das aspas duplas, portanto, a correção é fácil: use aspas duplas. Sempre coloque aspas duplas nas substituições de variáveis, a menos que você tenha um bom motivo para não fazê-lo.Por exemplo, se o diretório atual contiver os dois arquivos
A* algorithm.png
egraph1.png
, entãomv1 *.png
passaA* algorithm.png
como o primeiro argumento para a função egraph1.png
como o segundo argumento. Então$1
é dividido emA*
ealgorithm.png
. O padrãoA*
corresponde aA* algorithm.png
ealgorithm.png
não contém caracteres curinga. Assim, a função acaba sendo executada commv
os argumentos-n
,A* algorithm.png
,algorithm.png
e . Se você corrigir a função paratargetdir
-v
então ele irá mover corretamente o primeiro arquivo.
Para processar todos os argumentos, diga ao shell para processar todos os argumentos e não apenas o primeiro. Você pode usar
"$@"
para significar a lista completa de argumentos passados para a função.Isso está quase correto, mas ainda falha se um nome de arquivo começar com o caractere
-
, porquemv
tratará esse argumento como uma opção. Passe--
paramv
dizer “não há mais opções após este ponto”. Esta é uma convenção muito comum que a maioria dos comandos suporta.Um problema remanescente é que, se
mv
falhar, esta função retorna um status de sucesso, porque o status de saída dos comandos no lado esquerdo de um pipe é ignorado. No bash (ou ksh), você pode usarset -o pipefail
para fazer o pipeline falhar. Observe que definir essa opção pode fazer com que outro código em execução no mesmo shell falhe, portanto, você deve configurá-lo localmente na função, o que é possível desde o bash 4.4.Em versões anteriores, a configuração
pipefail
seria frágil, portanto, seria melhor verificarPIPESTATUS
explicitamente.$1
é o primeiro argumento para a função, aqui o primeiro arquivo que corresponde a*.png
. Eu acho que"$@"
é isso que você quer usar em vez de$1
.Você teria que usar
mv1 \*.png
.Ao interagir com funções, o Terminal Linux não passa o asterisco diretamente para o comando, mas seleciona o primeiro parâmetro correspondente e o passa para o comando.
Para permitir que o asterisco passe diretamente, é necessário escapar do asterisco usando uma barra invertida.