Fish Shell : Set formatted string to variable - fish

I want to open terminal with multiple instances of same server. For example, csshX server1 server1 server1
I'm trying to assign the formatted list of strings to single variable and use it in csshX.
#!/usr/local/bin/fish
set nmdat (echo 'server1 ' | string repeat -n (echo $countofinstance))
csshX $nmdat
But, this isn't helping. I have also tried
csshX (echo 'server1 ' | string repeat -n (echo $countofinstance))
This isn't working as well.

(echo $somevariable) can be written more simply as $somevariable
Try this: it should pass count individual arguments to the command:
set server server1
csshX (string repeat -n $count -N $server\n)
Demo:
$ set count 5
$ set string foo
$ bash -c 'echo $#; printf \'%s\\n\' "$#"' bash (string repeat -n $count "$string ")
1
foo foo foo foo foo
$ bash -c 'echo $#; printf \'%s\\n\' "$#"' bash (string repeat -n $count $string\n)
6
foo
foo
foo
foo
foo
# with an extra newline
$ bash -c 'echo $#; printf \'%s\\n\' "$#"' bash (string repeat -n $count -N $string\n)
5
foo
foo
foo
foo
foo

Related

Passing 'out' variables to function

I'm trying to make my fish_prompt fancier by having the colors of my username and host change depending on what they are. However, if this attempt fails, I'd rather leave the colors as defaults of $fish_color_[host|user] So far, this works:
function fish_prompt
# …
set -l color_host $fish_color_host
if command -qs shasum
set color_host (colorize (prompt_hostname))
end
# …
echo -n -s \
(set_color --bold $color_user) "$USER" \
(set_color normal) # \
(set_color $color_host) (prompt_hostname) \
' ' \
(set_color --bold $color_cwd) (prompt_pwd) \
(set_color normal) " $suffix "
end
function colorize
echo -n (printf "$argv" | shasum -ta 256 - | cut -c 59-64 | tr -d '\n')
end
At this point, I thought that this would look a lot cleaner if the shasum check were in colorize instead of being repeated in fish_prompt. I then tried this, figuring I might be able to pass the variable name if I single quoted it:
function fish_prompt
# …
set -l color_user $fish_color_user
colorize_more 'color_user' "$USER"
# …
end
function colorize_more -a what -a whence
if command -qs shasum
set "$what" (printf "$whence" | shasum -ta 256 - | cut -c 59-64 | tr -d '\n')
end
end
However, this doesn't appear to change $color_user in fish_prompt. I suspect that's because the set in colorize_more can't modify a variable that's local to the one in fish_prompt, as the color that should come out of colorize_more is a yellow instead of the green that I get from $fish_color_user.
How can I restructure my fish_prompt and accessory function(s) so that I have a colorize function that sets a variable to some value only if it is able to?
There are multiple possibilities here.
One is the "--no-scope-shadowing" flag to function
function colorize_more -a what -a whence --no-scope-shadowing
that will keep the outer local scope visible. This won't work with e.g. $argv, and if you need any variables they could potentially overwrite externally defined ones, so this is to be used with care.
Another is to define the variables as global instead - this has the disadvantage that they'll then stay defined and will conflict with any global variable of the same name.
Another is to output the value instead of assigning it.
E.g.
function colorize_more -a whence
if command -qs shasum
echo (printf "$whence" | shasum -ta 256 - | cut -c 59-64 | tr -d '\n')
end
end
set -l color_user (colorize_more $USER)
set -q color_user[1]; or set color_user $fish_color_user
# or you could let colorize_more output $fish_color_user if it wouldn't output anything else
Inspired by faho's comment of "Another is to output the value instead of assigning it", I ended up doing this:
function fish_prompt --description 'Write out the prompt'
# …
set -l color_host (colorize (prompt_hostname) "$fish_color_host")
set -l color_user (colorize "$USER" "$fish_color_user")
# …
end
function colorize -a what -a default -d 'Outputs a hex color for a string or, failing that, a default'
if command -qs shasum
echo -n (printf "$what" | shasum -ta 256 - | cut -c 59-64 | tr -d '\n')
else
echo "$default"
end
end

wc -c gives one more than I expected, why is that?

echo '2003'| wc -c
I thought it would give me 4, but it turned to be 5, what is that additional byte?
Because echo will get a new line.
echo "2014" | wc -c
it will get 5
printf "2014" | wc -c
it will get 4 where printf will not add a new line.
echo contains a built-in switch, -n, to remove newline. So running:
echo -n "2021" | wc -c
Will output the expected 4.
echo adds new line which is causing the issue.
As mentioned by "KyChen", you can use printf or:
a="2014 ;
echo $a |awk '{print length}'

assign actions to one sed address simultaneously for match and non-match

My sed command line script looks like
echo "a,b,c,d" | sed -ne 's/[^a-zA-Z0-9]//g; /^...$/ p; /^...$/! q1'
I want the script to succeed (return-code 0) if there are exactly 3 letters left, and to fail otherwise.
The slightly nagging part is that I have to duplicate the address /^...$/.
I was hoping for something like
echo "a,b,c,d" | sed -ne 's/[^a-zA-Z0-9]//g; /^...$/ p ! q1'
but that doesn't work, at least not with that syntax.
You can use // to represent previously used regex
$ echo "a,b,c,d" | sed -ne 's/[^a-zA-Z0-9]//g; /^...$/ p; //! q1'
$ echo $?
1
$ echo "b,c,d" | sed -ne 's/[^a-zA-Z0-9]//g; /^...$/ p; //! q1'
bcd
$ echo $?
0
Alternatively, you can use b command to start next cycle
$ echo "b,c,d" | sed -ne 's/[^a-zA-Z0-9]//g; /^...$/{p;b}; q1'
bcd
$ echo $?
0
$ echo "a,b,c,d" | sed -ne 's/[^a-zA-Z0-9]//g; /^...$/{p;b}; q1'
$ echo $?
1
This syntax will probably work with GNU sed only. See manual for details

Read variable further down in code in shell script

In a shell script I need to know the value of a variable further down in the code, without running through it first.
This pings $IP which is extracted from $VAR below the while loop.
The $VAR is unknown at the time this is extracted (IP=$(echo $VAR | awk '{print $1}'))
Is it possible to read VAR in before the while loop runs?
The code:
#!/bin/sh
TIMEOUT=10
IP=$(echo $VAR | awk '{print $1}')
while [ $TIMEOUT -ne 0 ];do
ping -c 1 -W 1 "$IP" >/dev/null
rc=$?
if [ $rc -eq 0 ];then
TIMEOUT=0
else
TIMEOUT=$(($TIMEOUT - 1))
echo $TIMEOUT
sleep 1
fi
done
# rest of code to run after while loop
VAR="192.168.0.1 t,r 20,e"

Add few line with in the middle of a file

I want to add few in a file. Is it possible to use sed?
original file
test1
test2
test3
Expected output after adding the new line
test1
#
testing123
#
test3
If you don't mind using "while/read" instead of "sed", this is one solution:
[~]$ cat original.txt
test1
test2
test3
[~]$ cat new_content.txt
#
testing123
#
Then, process both files with the following script:
script.sh
#!/bin/bash
while IFS= read -r line
do
if [[ $line =~ ^test2.*$ ]]
then
cat new_content.txt
else
echo "$line"
fi
done < original.txt
sed '2 i\
\
#
2 a\
#\
' YourFile
Arbitrary take the line 2 as middle (not easy to count or take middle in posix sed)
ifor insert (before)
a for append (after)