How to use grep in csh script - shell

Below is a simple csh script I wrote. But the set does not work. Can anyone please help me with the error.
#!/bin/csh
echo "hello"
set ans ='grep -r hello ./'
echo ans
Tried back quotes still not working:
#!/bin/csh
echo "hello"
set ans =`grep -r hello .`
echo $ans

To get the value of a variable you have to add a $ to the beginning:
echo $ans
Furthermore you should remove the space in front of the = sign:
set ans=`grep -r hello .`

You need to use backquotes `` and not simplequotes ''.
Also variables are instanciated without a dollar but you need to access them like $ans
#!/bin/csh
echo "hello"
set ans =`grep -r hello .`
echo $ans

Related

Bash appending extra characters to variable?

I'm trying to store values in variables and trying to echo result to a file. But when it's adding two variables and echoing it to a file, extra characters are being added to the output file. This is happening in docker container, Can some one please help...
IFS=" "
#while read line
while read c s e
do
echo $c $s $e
first=$(echo "PER_${s}_${e}")
#echo -n $first
second=$(echo "/IPD_${c}")
#echo $second
echo $first$second >> /mnt/resource/step2/messages.txt
done < /mnt/resource/step2/job_control/Categories.txt
Categories.txt contains :
129490 201515 201540
I'm getting the output as :
PER__/IPD_PER_201515_201540/IPD_12949029490
But it should be like:
PER_201515_201540/IPD_129490
I can't reproduce the problem, but your code is more complicated than it needs to be.
while IFS=" " read c s e; do
first="PER_${s}_${e}"
second="/IPD_${c}"
echo "$first$second" >> /mnt/resource/step2/messages.txt
done < /mnt/resource/step2/job_control/Categories.txt

How to echo (print) the value of a variable in Bash?

I am trying to write a little script, and I can not figure out how to choose the variable to be echo'ed (echo $'TEST'_"$response") dynamically depending on the user's input:
#!/usr/bin/env sh
response=response
TEST_1="Hi from 1!"
TEST_2="Hi from 2!"
while [ $response ]; do
read -p "Enter a choice between 1 - 2, or 'bye': " response
if [ $response = 'bye' ]; then
echo "See You !"; exit
elif [ $response -ge 1 ] && [ $response -le 2 ]; then
echo $'TEST'_"$response"
else
echo "Input is not a valid value."
fi
done
The desired output would be the value of one of the variables declared at the beginning of my script ("Hi from 1!" or "Hi from 2!"). Instead my script simple outputs the name of the variable as a string "TEST_1" or "TEST_2". I do not simply want to hardcode the variable that will be printed like:
if [ $response -ge 1 ]; then
echo $TEST_1
fi
since it is not scalable. Using backticks like
echo `$'TEST'_"$response"`
doesn't help either since bash will expect to run the result "TEST_1" or "TEST_2" as a command.
Any hint will be greatly appreciated.
You need indirect expansion, to be used with ${!var}:
$ TEST1="hello"
$ TEST2="bye"
$ v=1
$ var="TEST$v" #prepare the variable name of variable
$ echo ${!var} #interpret it
hello
$ v=2
$ var="TEST$v" #the same with v=2
$ echo ${!var}
bye
That is, you need to use a variable name of a variable and this is done with the indirect expansion: you use a variable with the name of the variable and then you evaluate it with the ${!var} syntax.
In your case, use:
myvar="TEST$response"
echo "${!myvar}"
Always use quotes, such as "$string", for anything other than numbers. For numbers, just keep it normal (i.e. $number).

Overwrite last line on terminal

My bash-script looks as following:
echo "Description:"
while [ $finishInput -eq 0 ]; do
read tmp
desc="$desc"$'\n'"$tmp"
if [ -z "$tmp" ]; then
finishInput="1"
fi
done
echo -n "Maintainer:"
read maintainer
It reads to the desc var until a empty line is passed. After that, i want to read in other stuff.
When executing my current script it looks like this:
Description:
Line 1
Line 2
Maintainer:
I would like to overwrite the last empty line with the "Maintainer:".
I searched for a solution but only found suggestions which were like
echo -n "Old line"
echo -e "\r new line"
which stays on the line and overwrites it. This is not possible in my case.
In your example you delete the text at the same line. When you want to return to the previous line use \e[1A, and to clear that line, use \e[K:
echo 'Old line'
echo -e '\e[1A\e[Knew line'
When you want to go N lines up, use \e[<N>A
Found a great guide on escape sequences and wanted to expand on some of the discussions here.
When you write out to a terminal, you move an invisible cursor around, much like you do when you write in any text editor. When using echo, it will automatically end the output with a new line character which moves the cursor to the next line.
$ echo "Hello" && echo " World"
Hello
World
You can use -n to prevent the new line and if you echo again after this, it will append it to the end of that line
$ echo -n "Hello" && echo " World"
Hello World
The cursor remains where it was so, on it's own, we can't use -n to overwrite the previous line, we need to move the cursor to the left. To do that we need to give it an escape sequence, which we let echo know we're going to use with -e and then move the cursor by providing a return carriage \r which puts the cursor at the beginning of the line.
$ echo -n "Hello" && echo -e "\rWorld"
World
That may look like it worked, but see what happens with
$ echo -n "A longer sentance" && echo -e "\rShort sentance"
Short sentancence
See the extra characters? Simply writing over the line only changes the characters where we wrote them.
To fix this, the accepted answer above uses the escape character \e[0K to erase everything after the cursor, after the cursor has moved left. i.e. \r move to beginning \e[0K erase to end.
$ echo -n "A longer sentance" && echo -e "\r\e[0KShort sentance"
Short sentance
Important \e to begin escape sequences works in zsh but not in sh and not necessarily in bash, however \033 works in all of them. If you want your script to work anywhere, you should preference \033
$ echo -n "A longer sentance" && echo -e "\r\033[0KShort sentance"
Short sentance
But escape characters can provide even more utility. For example \033[1A moves the cursor to the previous line so we don't need the -n on the previous echo:
$ echo "A longer sentance" && echo -e "\r\033[1A\033[0KShort sentance"
Short sentance
\r move to the beginning \033[1A move up \033[0K erase to the end
Finally, this is all a bit messy in my book, so you can turn this into a function:
overwrite() { echo -e "\r\033[1A\033[0K$#"; }
Using $# just puts all the parameters of the function into the string
$ echo Longer sentance && overwrite Short sentence
Short sentence
I built a function from Dennis Williamsons Comment:
function clearLastLine() {
tput cuu 1 && tput el
}
Thanks to Dennis Williamson
If you echo without the newline character echo -n "Something", you can use \r with your next echo to move the 'cursor' to the beginning of the line echo -e "\\rOverwrite something".
#!/bin/bash
CHECK_MARK="\033[0;32m\xE2\x9C\x94\033[0m"
echo -e "\n\e[4mDoing Things\e[0m"
echo -n "doing thing 1..."
sleep 1
echo -e "\\r${CHECK_MARK} thing 1 done"
Just be aware that if your new string is shorter that your old string, the tail of your old string will still be visible. Note the done.. in the gif above.
If you want to run a script in a loop and not blow up your scrollback, you can use the following pattern:
while sleep 10s; do
echo -n $(script)
echo -n -e "\e[0K\r"
done
Just replace the script command with your own.
#!/bin/bash
echo "Description:"
while test -z $finishInput; do
read -s tmp
desc="$desc"$'\n'"$tmp"
if [ -z "$tmp" ]; then
finishInput=1
else
echo $tmp
fi
#echo "fi="$finishInput;
done
echo -n "Maintainer:"
read maintainer
This solution avoids the empty line, but input is not echoed before the lines are complete.
Hint: My version of bash did not accept "[ $finishInput -eq 0 ]".

shell scripting string replace using shell variables

This is my very basic script:
temp=hello
while read line;
do
echo ${line}
done
However, ${line} will itself consist of "value of temp = ${temp}"
I want my script to echo "value of temp is hello". I've tried doing many things, even
echo `echo ${line}`
but each time it always just prints "value of temp is ${temp}"
I hope this question is clear. THanks!
What about this?
temp=hello
while read line; do
echo "Value of temp = `eval echo ${line}`"
done
Then in the console just type:
${temp}
Well, I have solutions with eval, but using eval is mauvais ton, actually.
$> cat 7627845.sh
#!/bin/bash
temp=hello
cat file_with_values.log | while read line;
do
eval echo "${line}"
done
$> cat file_with_values.log
value of temp = ${temp}
$> ./7627845.sh
value of temp = hello

Indirect parameter substitution in shell script

I'm having a problem with a shell script (POSIX shell under HP-UX, FWIW). I have a function called print_arg into which I'm passing the name of a parameter as $1. Given the name of the parameter, I then want to print the name and the value of that parameter. However, I keep getting an error. Here's an example of what I'm trying to do:
#!/usr/bin/sh
function print_arg
{
# $1 holds the name of the argument to be shown
arg=$1
# The following line errors off with
# ./test_print.sh[9]: argval=${"$arg"}: The specified substitution is not valid for this command.
argval=${"$arg"}
if [[ $argval != '' ]] ; then
printf "ftp_func: $arg='$argval'\n"
fi
}
COMMAND="XYZ"
print_arg "COMMAND"
I've tried re-writing the offending line every way I can think of. I've consulted the local oracles. I've checked the online "BASH Scripting Guide". And I sharpened up the ol' wavy-bladed knife and scrubbed the altar until it gleamed, but then I discovered that our local supply of virgins has been cut down to, like, nothin'. Drat!
Any advice regarding how to get the value of a parameter whose name is passed into a function as a parameter will be received appreciatively.
You could use eval, though using direct indirection as suggested by SiegeX is probably nicer if you can use bash.
#!/bin/sh
foo=bar
print_arg () {
arg=$1
eval argval=\"\$$arg\"
echo "$argval"
}
print_arg foo
In bash (but not in other sh implementations), indirection is done by: ${!arg}
Input
foo=bar
bar=baz
echo $foo
echo ${!foo}
Output
bar
baz
This worked surprisingly well:
#!/bin/sh
foo=bar
print_arg () {
local line name value
set | \
while read line; do
name=${line%=*} value=${line#*=\'}
if [ "$name" = "$1" ]; then
echo ${value%\'}
fi
done
}
print_arg foo
It has all the POSIX clunkiness, in Bash would be much sorter, but then again, you won't need it because you have ${!}. This -in case it proves solid- would have the advantage of using only builtins and no eval. If I were to construct this function using an external command, it would have to be sed. Would obviate the need for the read loop and the substitutions. Mind that asking for indirections in POSIX without eval, has to be paid with clunkiness! So don't beat me!
Even though the answer's already accepted, here's another method for those who need to preserve newlines and special characters like Escape ( \033 ): Storing the variable in base64.
You need: bc, wc, echo, tail, tr, uuencode, uudecode
Example
#!/bin/sh
#====== Definition =======#
varA="a
b
c"
# uuencode the variable
varB="`echo "$varA" | uuencode -m -`"
# Skip the first line of the uuencode output.
varB="`NUM=\`(echo "$varB"|wc -l|tr -d "\n"; echo -1)|bc \`; echo "$varB" | tail -n $NUM)`"
#====== Access =======#
namevar1=varB
namevar2=varA
echo simple eval:
eval "echo \$$namevar2"
echo simple echo:
echo $varB
echo precise echo:
echo "$varB"
echo echo of base64
eval "echo \$$namevar1"
echo echo of base64 - with updated newlines
eval "echo \$$namevar1 | tr ' ' '\n'"
echo echo of un-based, using sh instead of eval (but could be made with eval, too)
export $namevar1
sh -c "(echo 'begin-base64 644 -'; echo \$$namevar1 | tr ' ' '\n' )|uudecode"
Result
simple eval:
a b c
simple echo:
YQpiCmMK ====
precise echo:
YQpiCmMK
====
echo of base64
YQpiCmMK ====
echo of base64 - with updated newlines
YQpiCmMK
====
echo of un-based, using sh instead of eval (but could be made with eval, too)
a
b
c
Alternative
You also could use the set command and parse it's output; with that, you don't need to treat the variable in a special way before it's accessed.
A safer solution with eval:
v=1
valid_var_name='[[:alpha:]_][[:alnum:]_]*$'
print_arg() {
local arg=$1
if ! expr "$arg" : "$valid_var_name" >/dev/null; then
echo "$0: invalid variable name ($arg)" >&2
exit 1
fi
local argval
eval argval=\$$arg
echo "$argval"
}
print_arg v
print_arg 'v; echo test'
Inspired by the following answer.

Resources