Use Dollar and parenthesis inside string - zsh

Trying to define this alias in zsh
I think the problem is that inside the string, $(...) doesn't work properly
alias ss='sudo $(history -p \!\!)'
The output is the usage of sudo
usage: sudo -h | -K | -k | -V
usage: sudo -v [-AknS]
....

For listing the history on zsh according to this doc:
fc -ln <number>
the modifiers:
-n - removes the line counter
<number> - starts the history from this number historically (-1 is the last used)
for the purpose of the alias the solution is:
alias ss='sudo $(fc -ln -1)'
Special thanks to #ericnb

Related

.zshrc last line parse error near `\n' mac m1

As title. It seems that my .zshrc last line has some problem. No matter what the last line is, I receive the .zshrc:119: parse error near \n'` error. I'm using MAc M1 Max. Have googled some threads but all didn't work.
Example aliases
# alias zshconfig="mate ~/.zshrc"
# alias ohmyzsh="mate ~/.oh-my-zsh"
DEFAULT_USER="amber-moe"
if brew list | grep coreutils > /dev/null ; then PATH="$(brew --prefix coreutils)/libexec/gnubin:$PATH" alias ls='ls -F --show-control-chars --color=auto' eval `gdircolors -b $HOME/.dir_colors` fi
# The next line updates PATH for the Google Cloud SDK.
#if [ -f '/Users/xiaolang/google-cloud-sdk/path.zsh.inc' ]; then . '/Users/xiaolang/google-cloud-sdk/path.zsh.inc'; fi
# The next line enables shell command completion for gcloud.
if [ -f '/Users/xiaolang/google-cloud-sdk/completion.zsh.inc' ]; then . '/Users/xiaolang/google-cloud-sdk/completion.zsh.inc'; fi
This is the last line of my .zshrc. Thanks for helping me.
Are you using MSDOS endings? Seems like this is the problem
The problem isn't the last line; it's that your first if statement isn't terminated correctly, so zsh is still looking for the fi but finds the EOF instead.
The line
if brew list | grep coreutils > /dev/null ; then PATH="$(brew --prefix coreutils)/libexec/gnubin:$PATH" alias ls='ls -F --show-control-chars --color=auto' eval `gdircolors -b $HOME/.dir_colors` fi
Should actually be several lines:
if brew list | grep coreutils > /dev/null ; then
PATH="$(brew --prefix coreutils)/libexec/gnubin:$PATH"
alias ls='ls -F --show-control-chars --color=auto' eval `gdircolors -b $HOME/.dir_colors`
fi
(You can also add semicolons before alias and fi to achieve the same without breaking the line.)

dynamically pass string to Rscript argument with sed

I wrote a script in R that has several arguments. I want to iterate over 20 directories and execute my script on each while passing in a substring from the file path as my -n argument using sed. I ran the following:
find . -name 'xray_data' -exec sh -c 'Rscript /Users/Caitlin/Desktop/DeMMO_Pubs/DeMMO_NativeRock/DeMMO_NativeRock/R/scipts/dataStitchR.R -f {} -b "{}/SEM_images" -c "{}/../coordinates.txt" -z ".tif" -m ".tif" -a "Unknown|SEM|Os" -d "overview" -y "overview" --overview "overview.*tif" -p FALSE -n "`sed -e 's/.*DeMMO.*[/]\(.*\)_.*[/]xray_data/\1/' "{}"`"' sh {} \;
which results in this error:
ubs/DeMMO_NativeRock/DeMMO_NativeRock/R/scipts/dataStitchR.R -f {} -b "{}/SEM_images" -c "{}/../coordinates.txt" -z ".tif" -m ".tif" -a "Unknown|SEM|Os" -d "overview" -y "overview" --overview "overview.*tif" -p FALSE -n "`sed -e 's/.*DeMMO.*[/]\(.*\)_.*[/]xray_data/\1/' "{}"`"' sh {} \;
sh: command substitution: line 0: syntax error near unexpected token `('
sh: command substitution: line 0: `sed -e s/.*DeMMO.*[/](.*)_.*[/]xray_data/1/ "./DeMMO1/D1T3rep_Dec2019_Ellison/xray_data"'
When I try to use sed with my pattern on an example file path, it works:
echo "./DeMMO1/D1T1exp_Dec2019_Poorman/xray_data" | sed -e 's/.*DeMMO.*[/]\(.*\)_.*[/]xray_data/\1/'
which produces the correct substring:
D1T1exp_Dec2019
I think there's an issue with trying to use single quotes inside the interpreted string but I don't know how to deal with this. I have tried replacing the single quotes around the sed pattern with double quotes as well as removing the single quotes, both result in this error:
sed: RE error: illegal byte sequence
How should I extract the substring from the file path dynamically in this case?
To loop through the output of find.
while IFS= read -ru "$fd" -d '' files; do
echo "$files" ##: do whatever you want to do with the files here.
done {fd}< <(find . -type f -name 'xray_data' -print0)
No embedded commands in quotes.
It uses a random fd just in case something inside the loop is eating/slurping stdin
Also -print0 delimits the files with null bytes, so it should be safe enough to handle spaces tabs and newlines on the path and file names.
A good start is always put an echo in front of every commands you want to do with the files, so you have an idea what's going to be executed/happen just in case...
This is the solution that ultimately worked for me due to issues with quotes in sed:
for dir in `find . -name 'xray_data'`;
do sampleID="`basename $(dirname $dir) | cut -f1 -d'_'`";
Rscript /Users/Caitlin/Desktop/DeMMO_Pubs/DeMMO_NativeRock/DeMMO_NativeRock/R/scipts/dataStitchR.R -f "$dir" -b "$dir/SEM_images" -c "$dir/../coordinates.txt" -z ".tif" -m ".tif" -a "Unknown|SEM|Os" -d "overview" -y "overview" --overview "overview.*tif" -p FALSE -n "$sampleID";
done

zsh alias to remove all docker containers returns command not found

I have this alias in my .zshrc file:
alias rmcons="docker rm -f $(docker ps -aq)"
But after trying to execute it, it removes only one container and then it prints
$rmcons
ef8197f147fb
zsh: command not found: c2ea2673f9e4
zsh: command not found: 4603059f1618
zsh: command not found: 40ad60328595
How can I remove all containers that docker ps -aq shows?
You need to use single quotes ('') instead of double quotes ("").
alias rmcons='docker rm -f $(docker ps -aq)'
If you use double quotes, than the command substitution $(docker ps -aq) will be evaluated when you define the alias. In your example this was equivalent to
alias rmcons="docker rm -f ef8197f147fb
c2ea2673f9e4
4603059f1618
40ad60328595"
As the newlines are command separators (like ;) this alias is substituted by four commands: docker rm -f ef8197f147fb, c2ea2673f9e4, 4603059f1618 and 40ad60328595. The last three of which do not exist on your system, hence "command not found". It also means that the same output of docker ps -aq - as it was on alias definiton - will be used and not as it would be when running the alias.
On the other hand, if you use single quotes, the alias will actually substituted by the exact command you defined: docker rm -f $(docker ps -aq). Although docker ps -aq will still return output with newlines, these newlines are now only parsed word separators between arguments.
Warning: untested. I don't use/have docker.
I think you should serialize the output first "escaping" the new lines.
You might also use the for loop, trying:
for id in `docker ps -aq`; do docker rm -f $id; done
Note the backquotes to parse the command's output.
You can also directly use $() instead of its shortcut backquote.
I recommend to test with echo first instead of removing with rm:
for id in `docker -ps -aq`; do echo rm -f $id; done
, and to use the rm with its -i switch to prompt for confirmation before deleting.
I hope docker's rm subcommand has one.

unix command to extract part of a hostname

I would like to extract the first part of this hostname testsrv1
from testsrv1.main.corp.loc.domain.com in UNIX, within a shell script.
What command can I use? It would be anything before the first period .
Do you have the server name in a shell variable? Are you using a sh-like shell? If so,
${SERVERNAME%%.*}
will do what you want.
You can use cut:
echo "testsrv1.main.corp.loc.domain.com" | cut -d"." -f1
To build upon pilcrow's answer, no need for new variable, just use inbuilt $HOSTANME.
echo $HOSTNAME-->my.server.domain
echo ${HOSTNAME%%.*}-->my
Tested on two fairly different Linux's.
2.6.18-371.4.1.el5, GNU bash, version 3.2.25(1)-release (i386-redhat-linux-gnu)
3.4.76-65.111.amzn1.x86_64, GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
try the -s switch:
hostname -s
I use command cut, awk, sed or bash variables
Operation
Via cut
[flying#lempstacker ~]$ echo "testsrv1.main.corp.loc.domain.com" | cut -d. -f1
testsrv1
[flying#lempstacker ~]$
Via awk
[flying#lempstacker ~]$ echo "testsrv1.main.corp.loc.domain.com" | awk -v FS='.' '{print $1}'
testsrv1
[flying#lempstacker ~]$
Via sed
[flying#lempstacker ~]$ echo "testsrv1.main.corp.loc.domain.com" | sed -r 's#([^.]*).(.*)#\1#g'
testsrv1
[flying#lempstacker ~]$
Via Bash Variables
[flying#lempstacker ~]$ hostName='testsrv1.main.corp.loc.domain.com'
[flying#lempstacker ~]$ echo ${hostName%%.*}
testsrv1
[flying#lempstacker ~]$
You could have used "uname -n" to just get the hostname only.
You can use IFS to split text by whichever token you want. For domain names, we can use the dot/period character.
#!/usr/bin/env sh
shorthost() {
# Set IFS to dot, so that we can split $# on dots instead of spaces.
local IFS='.'
# Break up arguments passed to shorthost so that each domain zone is
# a new index in an array.
zones=($#)
# Echo out our first zone
echo ${zones[0]}
}
If this is in your script then, for instance, you'll get test when you run shorthost test.example.com. You can adjust this to fit your use case, but knowing how to break the zones into the array is the big thing here, I think.
I wanted to provide this solution, because I feel like spawning another process is overkill when you can do it easily and completely within your shell with IFS. One thing to watch out for is that some users will recommend doing things like hostname -s, but that doesn't work in the BSD userland. For instance, MacOS users don't have the -s flag, I don't think.
Assuming the variable $HOSTNAME exists, so try echo ${HOSTNAME%%.*} to get the top-most part of the full-qualified hostname. Hope it helps.
If interested, the hint is from the below quoted partial /etc/bashrc on a REHL7 host:
if [ -e /etc/sysconfig/bash-prompt-screen ]; then
PROMPT_COMMAND=/etc/sysconfig/bash-prompt-screen
else
PROMPT_COMMAND='printf "\033k%s#%s:%s\033\\" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
fi
;; ... ```

single quotes not working in shell script

I have a .bash_profile script and I can't get the following to work
alias lsls='ls -l | sort -n +4'
when I type the alias lsls
it does the sort but then posts this error message
"-bash: +4: command not found"
How do I get the alias to work with '+4'?
It works when type ls -l | sort -n +4 in the command line
I'm in OS X 10.4
Thanks for any help
bash-4.0$ ls -l | sort -n +4
sort: open failed: +4: No such file or directory
You need ls -l | sort -n -k 5, gnu sort is different from bsd sort
alias lsls='ls -l | sort -n -k 5'
Edit: updated to reflect change from 0 based indexing to 1 based indexing, thanks Matthew.
alias lsls='ls -l | sort -n +4' should work fine with the sort in OS X 10.4 (which does support that syntax).
when I type the alias lsls it does the sort but then posts this error message "-bash: +4: command not found"
Is it possible that you inserted a stray newline when editing your .bash_profile? e.g. if you ended up with something like this:
alias lsls='ls -l | sort -n
+4'
...that might explain the error message.
As an aside, you can get the same effect without piping through sort at all, using:
ls -lrS
This link discusses a very similar alias containing a pipe.
The problem may not have been the pipe, but the interesting solution was to use a function.

Resources