Comment exécuter une commande avec un répertoire en argument, puis cd sur le même? Je reçois "aucun fichier ou répertoire"

15

Je voudrais construire une fonction courte pour faire ce qui suit. Disons que je déplace le fichier 'file.tex' dans mon répertoire de documents:

mv file.tex ~/Documents

Ensuite, je voudrais cdà ce répertoire:

cd ~/Documents

Je voudrais généraliser cela à n'importe quel répertoire, afin de pouvoir le faire:

mv file.tex ~/Documents
follow

et demandez à la followcommande de lire la destination de la commande précédente, puis exécutez-la en conséquence. Pour un répertoire simple, cela ne fait pas gagner beaucoup de temps, mais lorsque vous travaillez avec des répertoires imbriqués, il serait formidable de pouvoir simplement utiliser

mv file.tex ~/Documents/folder1/subfolder1
follow

Je pensais que ce serait relativement simple et que je pourrais faire quelque chose comme ça:

follow()
{
    place=`history 2 | sed -n '1p;1q' | rev | cut -d ' ' -f1 | rev`
    cd $place
}

mais cela ne semble pas fonctionner. Si je fais écho $place, j'obtiens la chaîne souhaitée (je la teste ~/Documents), mais la dernière commande retourne

No such file or directory

Le répertoire existe certainement. Je suis à perte. Pourrais-tu m'aider?

Feu
la source
Je tiens à souligner que si cela ne vous dérange pas de rester file.texà l'emplacement d'origine, les liens symboliques sont une très bonne alternative, car vous ne devez créer un lien qu'une seule fois, puis il pointera toujours vers la dernière version.
Kroltan
5
Plus simple: tapez cd alt + .pour remplacer le dernier jeton de la commande précédente. Répétez pour remonter plus loin dans l'histoire des jetons finaux. (Je dis que le jeton n'est pas arg, car il foo &s'empare &du dernier jeton.) Vous pouvez utiliser un argument numérique (avec escape-3 alt +. Par exemple).
Peter Cordes
voir aussi combo cd mkdir
Christopher Bottoms

Réponses:

18

Au lieu de définir une fonction, vous pouvez utiliser la variable $_, qui est développée jusqu'au dernier argument de la commande précédente par bash. Alors utilisez:

cd "$_"

après mvcommande.

Vous pouvez également utiliser l'expansion de l'historique:

cd !:$

Si vous devez utiliser une fonction:

follow () { cd "$_" ;}

$ follow () { cd "$_" ;}
$ mv foo.sh 'foo bar'
$ follow 
foo bar$ 

NB: Cette réponse est ciblée sur le format d'arguments de ligne de commande exact que vous avez utilisé car nous traitons des paramètres de position. Pour d'autres formats, par exemple mv -t foo bar.txt, vous devez incorporer des vérifications spécifiques au préalable, un wrapper serait alors approprié.

heemayl
la source
Votre extension d'historique (cd!: $) Fonctionne parfaitement. Je vous remercie. Cependant, l'autre (cd "$ _") ne fonctionne pas: mv file.tex ~ / Downloads / cd "$ _" bash: cd: __bp_preexec_invoke_exec: Aucun fichier ou répertoire de ce type, j'accepterai très volontiers votre réponse comme entièrement correcte, et Merci.
Incendie du
J'ai toujours tapé (un peu de gaspillage) soit cd !$ou cd $(dirname !$). Ne connaissait pas la $_variable!
Kalvin Lee
Maintenant, que se passe-t-il si je le fais mv -t ~/Documents file.texau lieu de mv file.tex ~/Documents? En fin de compte, je ne suis pas sûr que cela soit résoluble dans le cas général ... une fonction wrapper autour ou que les réimplémentations mvpourraient être mieux ...
un CVn
@ MichaelKjörling Ne fonctionnera pas simplement .. cet exemple est juste pour couvrir le cas OP a, pas le bord (ou tous) les cas ..
heemayl
Vous n'avez pas besoin des deux points; !$est équivalent !:$et plus rapide à taper.
Wildcard
14

Avec les raccourcis clavier bash standard, la combinaison Alt.copiera le dernier argument de la ligne de commande précédente dans celui en cours. Donc, en tapant

$ mv foo ~/some/long/path/
$ cd <Alt><.>

donnerait

$ mv foo ~/some/long/path/
$ cd ~/some/long/path/

et serait encore moins tapant que le mot follow.

Pour plus de commodité, la répétition de la Alt.combinaison parcourra les derniers arguments de toutes les lignes de commande précédentes.

Addendum: le nom de la commande bash correspondant à cette combinaison de touches est yank-last-argou insert-last-argument. Il peut être trouvé dans la page de manuel bash sous "Commandes pour manipuler l'historique" ou dans le manuel de référence Bash plus exhaustif .)

Dubu
la source
1
C'est malin. Merci! Je n'avais aucune idée que cela existait.
Feu
@Fire J'ai ajouté des références pour ces commandes, afin que vous puissiez trouver des raccourcis clavier beaucoup plus intéressants (et les oublier immédiatement, comme je le fais toujours).
Dubu
1
Vous pouvez également utiliser <esc>ensuite .pour obtenir le même résultat que celui-ci <alt>+., utile lorsque vous avez remappé le verrou pour s'échapper :)
gnur
1
@gnur vi (m) utilisateur, je suppose. ;-)
Dubu
6

Vous rencontrez presque certainement le problème que l'expansion du tilde a lieu avant l'expansion des paramètres, ce qui peut être expliqué par un exemple succinct:

$ cd ~kaz
kaz $ var='~kaz'
kaz $ echo $var
~kaz
kaz $ cd $kaz
bash: cd: ~kaz: No such file or directory

Cela peut être résolu avec eval. Quoi qu'il en soit, vous allez avoir besoin eval, car vous tirez des commandes de l'historique et elles peuvent contenir des extensions arbitraires, comme:

$ mv file.tex ~/Documents/$(compute_folder_name foo-param)/subfolder1
$ follow

(Il y a des problèmes, tels que la ré-expansion de ces valeurs peut ne plus correspondre à l'expansion d'origine qui s'est produite. Supposons compute_folder_namequ'une fonction incrémente une variable globale.)

Kaz
la source
4
Tu n'as pas besoin eval. (Jamais.) Mais bon repérage des problèmes de séquence d'extension. Si vous mentionnez la plus grande opportunité d'expansion de l'histoire à utiliser evalici, ce sera la meilleure réponse à mon avis; aucun des autres n'a expliqué pourquoi la solution de l'affiche originale n'a pas fonctionné.
Wildcard