1

I have this function (defined inside my ~/.zshrc):

function graliases
{
    if [[ "$#*" -lt 1 ]]
    then
        echo "Usage: graliases <regex>"
    else
        echo "$*"
        grep -E '*"$*"*' ~/.dotfiles/zsh/aliases.zsh
    fi
}

What this function should do, is search the file ~/.dotfiles/zsh/aliases.zsh with a regex, provided by parameters. To the regex, two stars are appended and prepended, which should make the finding independet of the position in the line. My idea works, if i use plain grep:

$ grep -E '*git rebase*' ~/.dotfiles/zsh/aliases.zsh
    alias gr='git rebase'
    alias gra='git rebase --abort'
    alias grc='git rebase --continue'
    alias gri='git rebase --interactive'
    alias grs='git rebase --skip'


$ grep -E '*ls -la*' ~/.dotfiles/zsh/aliases.zsh
alias lnew='ls -ld *(/om[1,3])'     # Show three newest directories. "om" orders by modification. "[1,3]" works like Python slice.
alias lsize='ls -l */**(Lk+100)'    # List all files larger than 100kb in this tree
alias lvd='ls -ld **/*(/^F)'        # recursively list any empty sub-directories
alias l='ls -lph'                   # size,show type,human readable
alias la='ls -lAph'                 # long list,show almost all,show type,human readable
alias lt='ls -lAtph'                # long list,sorted by date,show type,human readable

The indentation in this grep example is as it should be, this is not an error. My function should basically do the same, just with the content between the two stars as parameters (in this case, git rebase and ls -la.

But it doesn't do the same, and i don't know why:

$ graliases git branch
git branch
alias lnew='ls -ld *(/om[1,3])'     # Show three newest directories. "om" orders by modification. "[1,3]" works like Python slice.
    alias findAllIPs="nmap -sP 192.168.1.* | grep -oE '192.168.1.[0-9]*'"
    alias findLocalIP="ifconfig | grep -oE 'inet 192.168.1.[0-9]*'"
    alias apls="apt list"
    alias gcR='git reset "HEAD^"'
    alias gdi='git status --porcelain --short --ignored | sed -n "s/^!! //p"'
    alias ggf="git ls-files | grep -i"
    alias gCl='git status | sed -n "s/^.*both [a-z]*ed: *//p"'
    alias gpc='git push --set-upstream origin "$(git-branch-current 2> /dev/null)"'
    alias gpp='git pull origin "$(git-branch-current 2> /dev/null)" 
          && git push origin "$(git-branch-current 2> /dev/null)"'
    alias gwig="git update-index --assume-unchanged"
    alias gwuig="git update-index --no-assume-unchanged"



% graliases ls -la
ls -la
alias lnew='ls -ld *(/om[1,3])'     # Show three newest directories. "om" orders by modification. "[1,3]" works like Python slice.
    alias findAllIPs="nmap -sP 192.168.1.* | grep -oE '192.168.1.[0-9]*'"
    alias findLocalIP="ifconfig | grep -oE 'inet 192.168.1.[0-9]*'"
    alias apls="apt list"
    alias gcR='git reset "HEAD^"'
    alias gdi='git status --porcelain --short --ignored | sed -n "s/^!! //p"'
    alias ggf="git ls-files | grep -i"
    alias gCl='git status | sed -n "s/^.*both [a-z]*ed: *//p"'
    alias gpc='git push --set-upstream origin "$(git-branch-current 2> /dev/null)"'
    alias gpp='git pull origin "$(git-branch-current 2> /dev/null)" 
          && git push origin "$(git-branch-current 2> /dev/null)"'
    alias gwig="git update-index --assume-unchanged"
    alias gwuig="git update-index --no-assume-unchanged"

According to 1, 2, $* is the correct variable for this use case. Even the line echo "$*" prints out the expected result. Unfortunately, i haven't found an explicit explanation of $* in the zsh manpage though.

Why does my function not work properly?

  • 1
    At first glance it seems that you need to change grep -E '*"$*"*' to grep -E '*'"$*"'*', but I don't understand why do you use *, at the beginning and end of the pattern, at all. Star * has nothing to do with position of the pattern in the line. – jimmij Jun 26 '16 at 11:50
  • @jimmij Ah, thanks. If i implement your suggestions, my function works. :) ==> Would you mind morphing your comment into an answer and elaborate a bit to improve the later reading of unexperienced users with the same problem? :) – toogley Jun 26 '16 at 11:55
  • @jimmij $#* is the size of the array $*. The array $* is exactly the same as $@, except that $@ is magically turned into $@[@], which causes multiple-word expansion even in double quotes. – Gilles Jun 26 '16 at 12:46
3

The grep pattern looks wrong. The rule of thumb of the command line is that everything inside single quotes is taken literally, whereas when not quoted or inside double quotes shell expand such string according to its rules (globing, splitting, parameter expansion etc.). In your case the command

grep -E '*"$*"*' ~/.dotfiles/zsh/aliases.zsh

means to pass to grep string *"$*"* literally, so that grep interprets this pattern as star, followed by double-quote, followed by dolar sign repeated zero or more times (*), followed by double quote repeated zero or more times (*). That is not what you expect.

You want to treat $* as a variable (double quoted in this case), so close single quoted string in front of it and open afterwards:

grep -E '*'"$*"'*' ~/.dotfiles/zsh/aliases.zsh

But I don't see the reason for those stars at all (you don't want to grep for stars, do you?), to me it looks that you can just simplify this to

grep -E "$*" ~/.dotfiles/zsh/aliases.zsh

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.