Getting a zsh alias including a pipe to execute - macos

I wanted a command that would quickly copy the current tmux window layout to the clipboard on Mac using zsh. I came up with the following:
tmux list-windows | awk '{print $7}' | sed 's/\]$//' | pbcopy
When I run this from the command line it works perfectly with an output like the following:
d97b,135x32,0,0[135x16,0,0{87x16,0,0,0,47x16,88,0,1},135x15,0,17{87x15,0,17,2,47x15,88,17,3}]
However, I can't seem to run it as an alias. If I add the line:
alias layout="tmux list-windows | awk '{print $7}' | sed 's/\]$//' | pbcopy"
to my .zshrc file when I run layout the command does not work as expected. It instead outputs the full tmux list-windows command with the word layout replacing the session name:
0: layout* (4 panes) [135x32] [layout d97b,135x32,0,0[135x16,0,0{87x16,0,0,0,47x16,88,0,1},135x15,0,17{87x15,0,17,2,47x15,88,17,3}]] #0 (active)
What am I doing wrong?
Thanks.

alex_i is correct, if you escape the $7 everything works.
alias layout="tmux list-windows | awk '{print \$7}' | sed 's/\]$//' | pbcopy"
Note the backslash before the $7.

Don't use an alias; use a function:
layout () {
tmux list-windows | awk '{print $7}' | sed 's/\]$//' | pbcopy
}
Then you don't need to worry about quoting.

Is your '$7' interpreted during the .zshrc loading ? Couldn't it be the issue ?

Related

How to figure out, why is my shell crash?

When I enter this command:
$ grep -n 'some search' $file | awk '{print 1}' | sed 's/://' | xargs -I{} vim +"{}" $file
It will open, but after quitting vim, the shell crash. It does not react to any input neither for Ctr-C. I have no idea why, how to find out? I suspect there is some infinite loop, because after reboot, there is a lot clearing in terminal. But really have no clue of the reason.
PS:
alias grep: alias grep='grep --color=auto -P'
alias sed: alias sed='sed -E'
No more aliases.
vi changes the terminal settings.
When you onlu want to go to the first match, you can use the linenumber with
vi +$(grep -n 'some search' .bashrc | cut -d: -f1 | head -1) .bashrc
This is still to complicated, you can jump to the match with
vi '/+some search/' "$file"
When you want to go to the second match, just use n.

how to pass values from stdout as parameter for the next command

i want to svn blame lines of code which include "todo | fixme"
i have the general flow of the script but struggle to combine it into one
finding the lines with "todo"
grep --color -Ern --include=*.{php,html,phtml} --exclude-dir=vendor "todo|TODO|FIXME" .
blame the line of code
svn blame ${file} | cat -n |grep ${linenumber}
i could get $file and $linenumber from the first command with awk, but i dont know how to pipe the values i extract with awk into the second command.
i am missing the glue to combine these commands into one "script" (- :
You can build the command with awk and then pipe it to bash:
grep --color -Ern --include=*.{php,html,phtml} --exclude-dir=vendor "todo|TODO|FIXME" . |\
awk -F: '{printf "svn blame \"%s\" | cat -n | grep \"%s\"\n", $1, $2}'
That prints one command per input line with the following format:
svn blame "${file}" | cat -n | grep "${linenumber}"
The varibales are replaces. When you execute the command as above they are only printed to the shell, that you can comfirm if everything is right. If yes add a last pipe to the in of the command that the ouput is redirected to bash. The complete command would look like this:
grep --color -Ern --include=*.{php,html,phtml} --exclude-dir=vendor "todo|TODO|FIXME" . |\
awk -F: '{printf "svn blame \"%s\" | cat -n | grep \"%s\"\n", $1, $2}' | bash
A small notice: I think you want to print the line number extracterd in the first command, aren't you? But grep ${linenumber} just gives the line containing the string ${linenumber}. To print only the linenumber use that command: sed -n "2p" to print line number 2 for example. The complete command would then look like this:
grep --color -Ern --include=*.{php,html,phtml} --exclude-dir=vendor "todo|TODO|FIXME" . |\
awk -F: '{printf "svn blame \"%s\" | cat -n | sed -n \"%sp\"\n", $1, $2}' | bash

Change output of whoami to uppercase in shell

I am trying to save the output of whoami to a different variable after changing it to uppercase. Please help me. I am newbie to shell scripting.
Thanks in advance.
Using pure bash
x=$(whoami)
v=${x^^}
Using tr
v=$(whoami | tr 'a-z' 'A-Z')
Or
v=$(whoami | tr [:lower:] [:upper:])
Using awk
v=$(whoami | awk '{print toupper($0)}')
Using perl
v=$(whoami | perl -e 'print uc <>')

issue with using double grave accent (backtick) in bash

I am trying to figure out which files I need to modify; so by that, I use sequences of grep commands. I want to find out which files contain both foo and bar. Therefore, my command is:
grep foo `grep bar * -l` | awk -F':' '{print $1}' | sort | uniq
This command gets me a big list that looks like this:
pageABC.txt
pageBCD.txt
pageDEF.txt
I want this output to be opened in emacs. So what I'd normally do is:
emacs ` whatever_was_in_my_output `
This command normally opens all the files.
If I try
emacs `grep foo `grep bar * -l` | awk -F':' '{print $1}' | sort | uniq `
Emacs won't even start. Maybe it's because of the double grave accents used.
Any ideas how to solve this?
Many Thanks,
D
You forgot to escape the inner command substitution:
emacs `grep foo \`grep bar * -l\` | awk -F':' '{print $1}' | sort | uniq`
In cases like this, I usually prefer the alternative command substition syntax, since it nests more easily:
emacs $(grep foo $(grep bar * -l) | awk -F':' '{print $1}' | sort | uniq)
Avoid backticks in bash, and use $(command) to run sub-commands. They nest properly, unlike backticks.

Extract the last directory of a pwd output

How do I extract the last directory of a pwd output? I don't want to use any knowledge of how many levels there are in the directory structure. If I wanted to use that, I could do something like:
> pwd
/home/kiki/dev/my_project
> pwd | cut -d'/' -f5
my_project
But I want to use a command that works regardless of where I am in the directory structure. I assume there is a simple command to do this using awk or sed.
Are you looking for basename or dirname?
Something like
basename "`pwd`"
should be what you want to know.
If you insist on using sed, you could also use
pwd | sed 's#.*/##'
If you want to do it completely within a bash script without running any external binaries, ${PWD##*/} should work.
Using awk:
pwd | awk -F/ '{print $NF}'
Should work for you:
pwd | rev | cut -f1 -d'/' - | rev
Reference:
https://stackoverflow.com/a/31728689/663058

Resources