Ich bin ziemlich neu bei zsh (bin gestern von bash umgestiegen)
Ich hatte eine Bash-Funktion in Bash wie
vl() { cmd=`echo $1 | sed -r 's/(.+):([0-9]+).+/\1 +\2/g'`; vim $cmd }
Dadurch wird im Wesentlichen ein Argument wie folgt umgewandelt:
vl ./manifests/production/test.pp:387:foobar # A output of $grep -iHn test
Zu
vim ./manifests/production/test.pp +387 #Aim is to open file at line-number 387
Die gleiche Funktion in zsh funktioniert nicht wie erwartet. Sie öffnet eine Datei mit dem Namen ./manifests/production/test.pp +387
in vim, anstatt eine Datei mit dem Namen zu öffnen, ./manifests/production/test.pp
an +387
die angehängt ist. Es scheint, als ob die Anführungszeichen angehängt werden $cmd
.
Es wäre toll, wenn jemand erklären würde, was hier passiert. Danke
Antwort1
In normalen Shells im Bourne-Stil wie der Bourne-Shell, Dash, Ksh und Bash $variable
bedeutet die Syntax: „Nimm den Wert der Variablen, teile ihn in einzelne Wörter auf, wobei die Zeichen von IFS
vorkommen, und behandle jedes Wort als Platzhaltermuster für Dateinamen und erweitere es, wenn es mit einer oder mehreren Dateien übereinstimmt.“ Wenn es variable
sich um ein Array handelt, geschieht dies mit dem ersten Element des Arrays und die anderen Elemente werden ignoriert.
In zsh $variable
bedeutet die Syntax „nimm den Wert der Variable, außer entferne ihn, wenn er leer ist“. Wenn variable
es sich um ein Array handelt, geschieht dies mit allen Elementen des Arrays. Zsh-Enthusiasten halten die Methode von zsh für besser.
In zsh können Sie $=variable
eine Worttrennung schreiben. Dies ist jedoch nicht die beste Methode für das, was Sie tun. Ihre Bash-Funktion kann mit Leerzeichen in Dateinamen nicht umgehen, und die Verwendung $=variable
in zsh würde dies auch nicht tun. Hier ist eine andere Methode zum Parsen des Arguments, die sowohl in Bash als auch in Zsh funktioniert und mit jedem Zeichen außer :
in einem Dateinamen zurechtkommt. Wenn das Argument zwei Doppelpunkte enthält, wird alles nach dem ersten Doppelpunkt entfernt und der Teil zwischen dem ersten und dem zweiten Doppelpunkt wird als separates Argument mit einem vorangestellten +
Zeichen angehängt. Es ist etwas länger als Ihr Code, aber weniger schwer zu verstehen und gerät nicht beim ersten Hinweis auf ein Leerzeichen in einem Dateinamen ins Stocken.
vl () {
local suffix
case $1 in
*:*:*) suffix=${1#*:};; set -- "${1%%:*}" "+${suffix%%:*}";;
esac
vim "$@"
}
Antwort2
Das ist eine knifflige Angelegenheit :) Eine Problemumgehung besteht darin, die Funktion folgendermaßen zu definieren:
vl() { cmd=$(echo $1 | sed -r 's/(.+):([0-9]+).+/\1 +\2/g'); eval "vim $cmd"; }
Beachten Sie, dass die Problemumgehung in der Verwendung von besteht eval
und nicht in den anderen geringfügigen Änderungen, die ich vornehmen musste, da mir die erforderlichen Stackexchange-Bearbeitungskenntnisse fehlen 8-)