Zsh fügt möglicherweise Anführungszeichen zum Variablenwert hinzu (funktioniert jedoch in Bash)

Zsh fügt möglicherweise Anführungszeichen zum Variablenwert hinzu (funktioniert jedoch in Bash)

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 +387in vim, anstatt eine Datei mit dem Namen zu öffnen, ./manifests/production/test.ppan +387die 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 $variablebedeutet die Syntax: „Nimm den Wert der Variablen, teile ihn in einzelne Wörter auf, wobei die Zeichen von IFSvorkommen, und behandle jedes Wort als Platzhaltermuster für Dateinamen und erweitere es, wenn es mit einer oder mehreren Dateien übereinstimmt.“ Wenn es variablesich um ein Array handelt, geschieht dies mit dem ersten Element des Arrays und die anderen Elemente werden ignoriert.

In zsh $variablebedeutet die Syntax „nimm den Wert der Variable, außer entferne ihn, wenn er leer ist“. Wenn variablees 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 $=variableeine 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 $=variablein 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 evalund nicht in den anderen geringfügigen Änderungen, die ich vornehmen musste, da mir die erforderlichen Stackexchange-Bearbeitungskenntnisse fehlen 8-)

verwandte Informationen