Um alias para mover arquivos e segui-los para o destino deles

1

Estou tentando escrever um script - ou um alias, para ser mais preciso -, o que me permite mover arquivos e seguir ( cd ) para o diretório de destino deles. A resposta aceita a essa pergunta sugere este código:

mvf() { mv "$@" && goto "$_"; }

onde goto é apenas uma variante mais segura de cd e $_ é o último argumento passado para o último comando.

Minha implementação derivada é esta:

alias mvaf="mv $@ && cd $_"

Observe que eu não citei $@ para não tentar mover um arquivo pelo nome de todos os argumentos. Eu tentei essa variante originalmente, mas o script falhou também. Se eu chamar a implementação acima com mvaf test1 test2 .. , ele gera (traduzido): “mv: Operando arquivo ausente”

Durante a depuração, tentei sem o cd e, de fato, o alias mvaf="mv $@ " , que basicamente está renomeando o mv , move os arquivos.

Gostaria de saber agora por que mv não tem um operando na minha primeira implementação e como isso pode ser causado pelo && .

    
por bleistift2 15.06.2017 / 21:49

4 respostas

5

O alias não suporta operandos como $ @ ou $ 1, $ 2, etc.

Seu comando

alias mvaf="mv $@ && cd $_"

é igual a mv ' ' && cd $_ porque $@ não é reconhecido pelo alias da maneira esperada.

Isso pode ser provado facilmente assim:

$ alias mvaf='echo "Part 1:" $@ && echo "Part 2: " $_'
$ mvaf file66 /tmp/
Part 1:
Part 2:  Part 1: file66 /tmp/
#Part 2 includes the previous executed command (echo "Part 1:" $@) & the text sent after alias name 

$ alias mvaf='echo "Part 1:" $@;echo "Part 2: "'
$ mvaf file66 /tmp/
Part 1:
Part 2:  file66 /tmp/

Por outro lado, isso funciona, mas não por causa de $ @

$ alias mvaf='echo "mv $@"'
$ mvaf file66 /tmp/
mv  file66 /tmp/

$ alias mvaf='echo "mv"'
$ mvaf file66 /tmp/
mv file66 /tmp/

Como ideia geral, o alias é um tipo de substituição simples.

Alias aa='command1;command2' , quando chamado como aa sometext , igual a command1;command2 sometext

Para fazer isso funcionar, você precisa fazer isso com uma função. Bash desencoraja o uso de alias e incentiva o uso de funções para esses trabalhos. Você pode colocar esta função no seu arquivo de perfil bash, e esta função pode ser chamada pelo nome diretamente do seu terminal, como você faria com qualquer alias:

mvcd() { mv "$1" "$2" && cd "$2"; }

Encadear os comandos mv e cd com && é importante aqui, pois && garante que o segundo comando cd será executado somente se o comando anterior mv tiver sido bem-sucedido.

Alternativamente, como já foi recomendado no link da resposta aceita na sua pergunta , você poderia fazer algo como

mvf() { mv "$@" && goto "$_"; }
goto() { [ -d "$1" ] && cd "$1" || cd "$(dirname "$1")"; }

Tenha cuidado com a divisão de palavras bash. Para fazer com que tal função funcione corretamente, você precisa inserir aspas duplas ao chamar a função se o arquivo que você vai mover ou o diretório para o qual o arquivo será enviado incluir espaço em seu nome.

$ mvcd() { echo "1=$1";echo "2=$2";echo "3=$3";echo "4=$4"; }

$ mvcd spaced file1 /spaced directory/
1=spaced
2=file1
3=/spaced
4=directory/

$ mvcd "spaced file1" "/spaced directory/"
1=spaced file1
2=/spaced directory/
3=
4=
    
por 16.06.2017 / 01:18
1

alias não considera $@ ou $_ (ou $anything ) especial, então eles são passados para o shell textualmente.

Assim, seu original:

alias mvaf="mv $@ && cd $_"

significa que:

mvaf f dst/

se transforma em:

mv $@ && cd $_ f dat/

Como é improvável que o $@ e o $_ sejam definidos, o shell interpreta assim:

mv && cd f dat/

assim mv é chamado sem um argumento e lança o erro "Operando arquivo ausente".

Quando você redefine como:

alias mvaf="mv $@ "

e execute:

mvaf f dst/

ele se transforma em:

mv $@ f dst/

que, como antes, reduz para:

mv f dst/

e engana você para pensar que funcionou!

    
por 16.06.2017 / 01:29
0

Como @Deathgrip escreveu em comentário,

There is no mechanism for using arguments in the replacement text. If arguments are needed, a shell function should be used (see FUNCTIONS below).

Como funcionam os aliases?

Vamos pensar no que acontecerá quando você digitar as duas linhas a seguir na linha de comando:

$ alias word1="echo example"

$ word1 word2 word3

Ao executar o primeiro comando, bash lembra que sempre que word1 for a primeira palavra de qualquer comando, ele deverá substituí-lo por echo example . Quando ele vê o segundo comando, em primeiro lugar, ele executa a substituição da maneira mais simples (mais simples) possível - cria um comando echo example word2 word3 dessa entrada. Portanto, ecoa example word2 word3 .

Agora, o que acontece com o seu alias?

Quando ele vê mfav one two , apenas avalia mv $@ && cd $_ one two . Como $@ está vazio (tente echo $@ no console), mv falha. cd também falha, pois recebe mais argumentos do que um.

Nota: Eu simplifiquei muito a escrita que substitui apenas a primeira palavra. Para situações em que essa regra é violada, veja minha outra resposta .

    
por 16.06.2017 / 01:35
0

Todas as outras respostas explicam porque o pseudônimo não está funcionando, e a resposta de George Vasiliou dá uma função alternativa que faz o trabalho.

Eu queria aproveitar essa resposta, no entanto, para torná-la mais robusta. Atualmente, a função

mvcd() { mv "$1" "$2" && cd "$2"; }

não funcionará se o destino for um arquivo. Para corrigir isso, podemos usar a notação de substring de variável bash:

mvcd() { mv "$1" "$2" && [[ -d $2 ]] && cd $2 || cd ${2%/*}; }

Para ver o que está acontecendo aqui, vamos escrevê-lo em um formato um pouco mais legível:

mvcd () {
    mv "$1" "$2";     # Do the move
    if [[ -d $2 ]]    # Check if arg $2 is a dir
    then
        cd $2;        # if it is, cd into it
    else
        cd ${2%/*};   # else remove the filename and cd
    fi;
}

Verificamos se o destino é um diretório [1] - e, se for, simplesmente fazemos o cd. Se não for, então subseqüentes o segundo argumento do início para o mais à direita / e cd para isso.

[1] Perdi uma quantidade de tempo embaraçosamente tentando fazê-lo sem o condname e o link de ligação condicionais, ou simplesmente sempre colocando o ./ no caminho ou em outros hacks, mas sempre tive um problema - seja seria cd muito atrás (no caso de readlink) ou não funcionaria com cding para .. , ou não funcionaria com nomes de arquivos ou ... sim. Se alguém pode fazê-lo sem o condicional, estou muito aberto a sugestões.

    
por 16.06.2017 / 11:15