How do I echo $command without breaking the layout - bash

I'm trying to do the following in a bash script:
com=`ssh host "ls -lh"`
echo $com
It works, but the echo will break the output (instead of getting all lines in a column, I get them all in a row).
If I do: ssh host ls -lh in the CLI it will give me the correct output and layout.
How can I preserve the layout when echoing a variable?

You need:
echo "$com"
The quotes make the shell not break the value up into "words", but pass it as a single argument to echo.

Put double quotes around $com:
com=`ssh host "ls -lh"`
printf "%s" $com | tr -dc '\n' | wc -c # count newlines
printf "%s" "$com" | tr -dc '\n' | wc -c
echo "$com"

Related

Duplicate the output of bash script

Below is the piece of code of my bash script, I want to get duplicate output of that script.
This is how my script runs
#bash check_script -a used_memory
Output is: used_memory: 812632
Desired Output: used_memory: 812632 | used_memory: 812632
get_vals() {
metrics=`command -h $hostname -p $port -a $pass info | grep -w $opt_var | cut -d ':' -f2 > ${filename}`
}
output() {
get_vals
if [ -s ${filename} ];
then
val1=`cat ${filename}`
echo "$opt_var: $val1"
# rm $filename;
exit $ST_OK;
else
echo "Parameter not found"
exit $ST_UK
fi
}
But when i used echo "$opt_var: $val1 | $opt_var: $val1" the output become: | used_memory: 812632
$opt_var is an argument.
I had a similar problem when capturing results from cat with Windows-formatted text files. One way to circumvent this issue is to pipe your result to dos2unix, e.g.:
val1=`cat ${filename} | dos2unix`
Also, if you want to duplicate lines, you can use sed:
sed 's/^\(.*\)$/\1 | \1/'
Then pipe it to your echo command:
echo "$opt_var: $val1" | sed 's/^\(.*\)$/\1 | \1/'
The sed expression works like that:
's/<before>/<after>/' means that you want to substitute <before> with <after>
on the <before> side: ^.*$ is a regular expression meaning you get the entire line, ^\(.*\)$ is basically the same regex but you get the entire line and you capture everything (capturing is performed inside the \(\) expression)
on the <after> side: \1 | \1 means you write the 1st captured expression (\1), then the space character, then the pipe character, then the space character and then the 1st captured expression again
So it captures your entire line and duplicates it with a "|" separator in the middle.

why shell for expression cannot parse xargs parameter correctly

I have a black list to save tag id list, e.g. 1-3,7-9, actually it represents 1,2,3,7,8,9. And could expand it by below shell
for i in {1..3,7..9}; do for j in {$i}; do echo -n "$j,"; done; done
1,2,3,7,8,9
but first I should convert - to ..
echo -n "1-3,7-9" | sed 's/-/../g'
1..3,7..9
then put it into for expression as a parameter
echo -n "1-3,7-9" | sed 's/-/../g' | xargs -I # for i in {#}; do for j in {$i}; do echo -n "$j,"; done; done
zsh: parse error near `do'
echo -n "1-3,7-9" | sed 's/-/../g' | xargs -I # echo #
1..3,7..9
but for expression cannot parse it correctly, why is so?
Because you didn't do anything to stop the outermost shell from picking up the special keywords and characters ( do, for, $, etc ) that you mean to be run by xargs.
xargs isn't a shell built-in; it gets the command line you want it to run for each element on stdin, from its arguments. just like any other program, if you want ; or any other sequence special to be bash in an argument, you need to somehow escape it.
It seems like what you really want here, in my mind, is to invoke in a subshell a command ( your nested for loops ) for each input element.
I've come up with this; it seems to to the job:
echo -n "1-3,7-9" \
| sed 's/-/../g' \
| xargs -I # \
bash -c "for i in {#}; do for j in {\$i}; do echo -n \"\$j,\"; done; done;"
which gives:
{1..3},{7..9},
Could use below shell to achieve this
# Mac newline need special treatment
echo "1-3,7-9" | sed -e 's/-/../g' -e $'s/,/\\\n/g' | xargs -I# echo 'for i in {#}; do echo -n "$i,"; done' | bash
1,2,3,7,8,9,%
#Linux
echo "1-3,7-9" | sed -e 's/-/../g' -e 's/,/\n/g' | xargs -I# echo 'for i in {#}; do echo -n "$i,"; done' | bash
1,2,3,7,8,9,
but use this way is a little complicated maybe awk is more intuitive
# awk
echo "1-3,7-9,11,13-17" | awk '{n=split($0,a,","); for(i=1;i<=n;i++){m=split(a[i],a2,"-");for(j=a2[1];j<=a2[m];j++){print j}}}' | tr '\n' ','
1,2,3,7,8,9,11,13,14,15,16,17,%
echo -n "1-3,7-9" | perl -ne 's/-/../g;$,=",";print eval $_'

SHELL: Variable output

I need help. I have this shell script that will output the hdd status, but the variable $disk is not read in the echo to show result.
disk="sda1"
echo -n $(df -hl | grep '$disk' | awk ' {percent+=$5;} END{print percent}'| column -t ):
In bash, variables are not expanded when put inside single quotes. Use double quotes:
echo -n $(df -hl | grep "$disk")

using rot13 and tr command for having an encrypted email address

I have read many tutorials on the internet about the usage of the 'tr' command.
However, I am not able to understand how to encrypt an email address with a shell script shift the characters using rot13. Can any one give a link or an example?
Not sure exactly how you want to use this, but here's a basic example to get you started:
echo 'fooman#example.com' | tr 'A-Za-z' 'N-ZA-Mn-za-m'
To make it easier, you can alias the tr command in your .bashrc file thusly:
alias rot13="tr 'A-Za-z' 'N-ZA-Mn-za-m'"
Now you can just call:
echo 'fooman#example.com' | rot13
A perfect task for tr, indeed. This should do what you want:
tr 'A-Za-z' 'N-ZA-Mn-za-m'
Each character in the first set will be replaced with the corresponding character in the second set. E.g. A replaced with N, B replaced with O, etc.. And then the same for the lower case letters. All other characters will be passed through unchanged.
Note the lack of [ and ] where you normally might expect them. This is because tr treats square brackets literally, not as range expressions. So, for example, tr -d '[A-Z]' will delete capital letters and square brackets. If you wanted to keep your brackets, use tr -d 'A-Z':
$ echo "foo BAR [baz]" | tr -d '[A-Z]'
foo baz
$ echo "foo BAR [baz]" | tr -d 'A-Z'
foo [baz]
Same for character classes. E.g. tr -d '[[:lower:]]' is probably an error, and should be tr -d '[:lower:]'.
However, in lucky situations like this one, you can get away with including the brackets anyway! For example, tr "[a-z]" "[A-Z]" accidentally works because the square brackets in the first set are replaced by identical square brackets from the second set, but really this is a bad habit to get into. Use tr "a-z" "A-Z" instead.
Ruby(1.9+)
$ ruby -ne 'print $_.tr( "A-Za-z", "N-ZA-Mn-za-m") ' file
Python
$ echo "test" | python -c 'import sys; print sys.stdin.read().encode("rot13")'
to simultaneously do ROT13 (for letters) and ROT5 (for numbers):
tr 'A-Za-z0-9' 'N-ZA-Mn-za-m5-90-4'
usage:
echo test | tr 'A-Za-z0-9' 'N-ZA-Mn-za-m5-90-4'
alias definition for your ~/.bashrc in case you need it more often:
alias rot="tr 'A-Za-z0-9' 'N-ZA-Mn-za-m5-90-4'"
(accurately rot135 or rot18)
# Reciprocal Transformation(s)
# rot13
tr 'A-Za-z' 'N-ZA-Mn-za-m' <<< 'user#domain.com'
# rot13.5 (rot18)
tr 'A-Za-z0-9' 'N-ZA-Mn-za-m5-90-4' <<< 'user123#domain.com'
# rot47
tr '\!-~' 'P-~\!-O' <<< 'user123#domain.com'
# rot13 -- SED anyone
echo 'user#domain.com' | sed y/NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/
Shell Script
#!/bin/bash
# Purpose: Rotate 13 characters (a reciprocal transformation)
# ./rot13.sh 'A String to look Ciphered'
tr 'A-Za-z' 'N-ZA-Mn-za-m' <<< "$1"
exit $?
You can execute it inside a shell script
#!/bin/bash
echo 'rot13#rot.com' | tr 'A-Za-z' 'N-ZA-Mn-za-m'
echo 'rot13#rot.com' | rot13
Make the file executable by running:
sudo chmod +x file_name
To ouput the answer run:
./file_name
example:
./try.sh

set variable in heredoc section

I'm a shell script newbie, so I must be doing something stupid, why won't this work:
#!/bin/sh
myFile=$1
while read line
do
ssh $USER#$line <<ENDSSH
ls -d foo* | wc -l
count=`ls -d foo* | wc -l`
echo $count
ENDSSH
done <$myfile
Two lines should be printed, and each should have the same value... but they don't. The first print statement [the result of ls -d foo* | wc -l] has the correct value, the second print statement is incorrect, it always prints blank. Do I need to do something special to assign the value to $count?
What am I doing wrong?
Thanks
#!/bin/sh
while read line; do
echo Begin $line
ssh $USER#$line << \ENDSSH
ls -d foo* | wc -l
count=`ls -d foo* | wc -l`
echo $count
ENDSSH
done < $1
The only problem with your script was that when the heredoc token is not quoted, the shell does variable expansion, so $count was being expanded by your local shell before the remote commands were shipped off...

Resources