Count number of slashes in string with zsh - zsh

I try to get the number of slashes in a string with zsh. I thought it should work like this (replace all non / chars and then count them)
foo="sdfds/sf/sdf/sdf/sd/f//sdf/"
print ${#foo//[^/]/}
But i get preexec:26: bad pattern: [^. It seems to work for all characters except /. I tried to escape it with backslashes but it did not work until I added 3 backslashes:
print ${#foo//[^\\\/]/}
Why do I need to find an escaped slash in the string?
edit: Yes, it seems to work with one backslash using zsh -f.
My setopt:
autocd
autopushd
nobeep
completeinword
correct
extendedglob
extendedhistory
nohistbeep
histfindnodups
histignorealldups
histignoredups
histignorespace
histnofunctions
histnostore
histreduceblanks
histsavenodups
histverify
nohup
incappendhistory
interactive
interactivecomments
longlistjobs
monitor
nonomatch
promptsubst
pushdignoredups
sharehistory
shinstdin
transientrprompt
zle

Related

Zsh oneliner to Extract part of string until and including token

I need a solution in zsh
I have a string like http://xxx.abc.mp3?yyy:mno. Is there a one-liner in zsh that can extract the string until mp3, that http://xxx.abc.mp3? I can do this in bash, but I needed a way to do it in zsh.
You didn't say how you did it in bash, but the same substitution works with both shells:
str='http://xxx.abc.mp3?yyy:mno'
printf "%s\n" "${str/%\?*}"
Removes the text that matches a question mark and 0 or more characters until the end of the string.

how to echo literal variable value with zsh

I have a simple shell function to convert a *nix style path to Windows style (I happen to be using Windows Subsystem for Linux).
# convert "/mnt/c/Users/josh" to "C:\Users\josh"
function winpath(){
enteredPath=$1
newPath="${enteredPath/\/mnt\/c/C:}" # replace /mount/c/ with C:
newPath="${newPath//\//\\}" # replace / with \
echo $newPath
}
The desired behavior is:
$ winpath /mnt/c/Users/josh
C:\Users\josh
This works correctly in bash, but in zsh, echo seems to do some extra interpolation of the $newPath value. It behaves like this:
$ winpath /mnt/c/Users/josh
C:sers\josh
What character sequence is echo interpolating and why is it remove the \U? Most importantly, how do I return the literal value?
I've tried digging through the zsh documentation, but it's a jungle. Thanks in advance!
zsh processes certain escape sequences that bash does not by default. \U introduces 4-byte Unicode codepoint, but since the following 8 characters are not a valid hexadecimal number, no character is substituted.
I would recommend using printf, as its behavior is much more predictable from shell to shell.
printf '%s\n' "$newPath"
The problem is that you are using the internal command echo, instead of the external one. If you would write
command echo $newPath
you would get the expected output. command forces zsh to look up the command word according to the current PATH, ignoring internal commands, aliases or functions of the same name.

Find and replace: \'

I'm trying to replace a every reference of \' with ' in a file
I've used variations of: sed -e s/\'/"\'"/g file.txt
But they always replace every.single.(single).quote
Any help would be greatly appreciated.
Not sure it's the best solution,I could do it like this:
sed "s/[\]'/\"\'\"/g" file.txt
(putting the backslash character in a character range so it doesn't interfere with the following quote, and protect with double quotes)
Or just extending your syntax, without quotes but using almost the same trick:
sed -e s/[\\]\'/"\'"/g file.txt
An approach trying to conserve as much of the "single-quotedness" of the sed command as possible:
sed 's/\\'"'"'/\'/g'
Just escaping \ with \\ and getting a single quote into the command with '"'"': the first single quote ends the command so far, then we have a double-quoted single quote ("'"), and finally an opening single quote for the rest of the command.
Alternatively, double quoting the whole command and escaping both the backslash and single quote:
sed "s/\\\'/\'/g"
The correct syntax is:
$ echo "foo'bar" | sed 's/'\''/\'/'
foo'bar
Every script (sed, awk, whatever) should always be enclosed in single quotes and you just us other single quotes to stop/restart the script delimiters break out to shell for the minimal portion of the script that's absolutely necessary, in this case long enough to use \'. You need to break out to shell to specify that ' because per shell rules no script enclosed in 's can contain a ', not even if you try to escape it.
echo "foo'bar" | gawk '{gsub(/\47/,"\\'")}1'
foo'bar
The tricky part here is to replace a single quote with ampersand.
First in order to make the single quote manageable use its octal
code here \47 and then escaping ampersand by two back slash. And all of sudden
it becomes feasible :)

How to include multiple backslashes in Unix Korn Shell

I have the following variables in Unix Korn Shell
host=nyc43ksj
qry_dir='\test\mydoc\mds'
fullpath="\\$host\$qry_dir"
echo "$fullpath"
When I execute the above, I get output such as \nyc43ksj\qrydir.
It looks like the backslashes are used as escape characters.
I tried changing fullpath as follows:
fullpath="\\$host\\$qry_dir"
echo "$fullpath"
This time I get \nyc43ksj\test\mydoc\mds. However, the two backslashes at the beginning are not display as two backslashes. How can get the fullpath as \\nyc43ksj\test\mydoc\mds (two backslashes at the beginning).
In a string, the \ (backslash) character acts as an escape character (as you mention), and the second backslash instructs the shell to put in an actual backslash, as opposed to some special character.
If you want to have two actual backslash characters in the string in sequence, you will need to put \\\\ in the string, so:
fullpath="\\\\$host\\$qry_dir"

SED character after the substitute command ("s")

I know about s// type command in sed, however never saw using s#. Could someone explain what exactly this is doing?
% sed -e "s#SRC_DIR=.*#SRC_DIR=$PROJECT_SRC_DIR#g" -i proj.cfg
I understand that -e defines a script to execute, and the script is withing "", but what exactly s# does?
Checked http://www.grymoire.com/Unix/Sed.html and gnu website, but no luck.
# is a sed delimiter like /. We could use ~, #, /, ;, etc as sed delimiters. They uses a different delimiter # because they don't want to escape / slashes. If you use # as delimiter, you don't need to escape / forward slash. But if you use / as delimiter, you must need to escape / as \/ or otherwise sed would consider / as delimiter.
From sed's manual:
The syntax of the s (as in substitute) command is ‘s/regexp/replacement/flags’. The / characters may be uniformly replaced by any other single character within any given s command. The / character (or whatever other character is used in its stead) can appear in the regexp or replacement only if it is preceded by a \ character.

Resources