evaluating lines from stdout - bash

I have a bash script that is executing a program in a loop. I want to evaluate each line from the stdout and do something if it matches my condition.
I still want to be able to see stdout on the screen. Is there a simple way to accomplish this? Thanks!

There are several variants of looping over input, but one possibility is thus:
my_cmd | while read line; do
echo "$line"
my_process "$line"
done

This should do what you want:
for string in "a" "b" "c"
do
output=`echo ${string}`
echo ${output}
if [ ${output} == "b" ] ; then
echo "do something"
fi
done
Just replace the first echo with your program.

Related

Bash Script Not Concatenating String as Intended [duplicate]

I have a code like that
var="before"
echo "$someString" | sed '$someRegex' | while read line
do
if [ $condition ]; then
var="after"
echo "$var" #first echo
fi
done
echo "$var" #second echo
Here first echo print "after", but second is "before". How can I make second echo print "after". I think it is because of pipe buy I don't know how figure out.
Thanks for any solutions...
answer edit:
I corrected it and it works fine. Thanks eugene for your useful answer
var="before"
while read line
do
if [ $condition ]; then
var="after"
echo "$var" #first echo
fi
done < <(echo "$someString" | sed '$someRegex')
echo "$var" #second echo
The reason for this behaviour is that a while loop runs in a subshell when it's part of a pipeline. For the while loop above, a new subshell with its own copy of the variable var is created.
See this article for possible workarounds: I set variables in a loop that's in a pipeline. Why do they disappear after the loop terminates? Or, why can't I pipe data to read?.

Why is my variable not holding its value in bash?

I am horribly perplexed.
I've written a bash script to sort lines into categories based on substrings within that line.
Here's my example "lines.txt"
i am line1
i am line2
If a line contains "line1", then it should be sorted into group "l1". If it contains "line2", then it should be sorted into group "l2"
The problem is that the variable which holds the category isn't retaining its value, and I have no clue why. Here's the script.
#!/bin/bash
categories="l1 l2"
l1="
line1
"
l2="
line2
"
# match line1
cat lines.txt | while read fline
do
cate="no match"
for c in $categories
do
echo "${!c}" | while read location
do
if [ ! -z "$location" ] && [[ "$fline" =~ "$location" ]]
then
echo "we are selecting category $c"
cate="$c"
break
fi
done
if [ "$cate" != "no match" ]
then
echo "we found a match"
break
fi
done
echo "$cate:$fline"
done
exit 0
And when I run it, I see the output
we are selecting category l1
no match:i am line1
we are selecting category l2
no match:i am line2
This means that we are selecting the correct group, but we don't remember it when we exit the nested "while" loop.
Why is my variable not retaining its value, and how could I fix that?
The while loop is executed in a subshell because of the pipe. That means that the name 'cate' really refers to two different variables. One outside the while loop and the other inside the loop inside the subshell. When the subshell exits that value is lost.
A way to get around this is to use a redirect like this
while read line; do
...
done < $myfile
If the expression is more complicated and you need something executed in a subshell, then you can use process substitution (Thanks to David Rankin for reminding me about this one).
while read -r line; do
...
done < <(find . -iname "*sh")

How to make multiple search and replace in files via bash

i have script. In this script i made search and replace of words. Word by word until word 'end'. It is ok and it works. You can see body of my script:
#!/bin/bash
end=end
until [ "$first" = "$end" ];do
echo "please write first word";
read first
if grep -q "$first" *txt; then
echo "word is exists"
grep "$first" *txt
echo "please write second word";
read second
sed -i 's/'"$first"'/'"$second"'/g' *txt
else
echo "second word does not exists"
exit 1
fi
done
It works for me. I have in the result console, where I can endlessly loop words, but if i want to do something like this: How can i write multiple words in line.
For example: "dog" "cat" "fish"
And search and replace all of these words. How can do it? For example, if i need to replace on these words ("elephat" "mouse" "bird"). How can you do it?
I mean search and replace words, like arguments.
You just need a loop to process the arguments.
Assuming you run the script passing pairs of original replacement words (myscript.sh original_word1 replacement1 original_word2 replacement2 ...) it would be something like the following:
while [[ $# -gt 1 ]]
do
original="$1"
replacement="$2"
# your code for actually replacing $original with $replacement
shift # discard already processed original arg
shift # discard already processed replacement arg
done
Note that if the user passes a last original word without replacement the script will just ignore it
Your English is rough, but I think you want to be able to prompt for multiple words, and replace them with a new set?
The below code will let you run a program like replace_words one two three and then be prompted for a list of words to replace, e.g. 1 2 3. After that, it exits.
declare -a replace_list=( "$#" ) # get the replace list as passed arguments
echo -n "Enter words to replace with: "; read -ra sub_list
for ((i=0; i < "${#replace_list[#]}"; ++i)); do
if grep -q "${replace_list[$i]}" *txt; then
echo "first word is exists"
sed -i "s/${replace_list[$i]}/${sub_list[$i]}/g" *txt
else
echo "${replace_list[$i]} does not exists"
exit 1
fi
done

How to remove contact from shell script?

I am creating a simple phonebook using unix shell scripts. I have gotten all of my functions to work except the removal of a contact after it has been created. I have tried combining grep and sed in order to accomplish this, but cannot seem to get over the hump. The removal shell i've tried is as follows.
#!/bin/sh
#removeContact.sh
echo “Remove Submenu”
echo “Please input First Name:”
read nameFirst
echo “Please input Last Name:”
read nameLast
x=$(grep -e “$nameFirst” -e “$nameLast” ContactList)
echo $x
sed '/'$x'/ d' ContactList;
echo “$nameFirst $nameLast is removed from your contacts”
exit 0
I'm not sure if I am declaring x incorrectly, or if my syntax is wrong when sed is used.
Any help would be greatly appreciated. Thank you.
#!/bin/bash
ContactList="contacts.txt"
export ContactList
exit=0
while [ $exit -ne 1 ]
do
echo "Main Menu"
echo "(a) Add a Contact"
echo "(r) Remove a Contact"
echo "(s) Search a Contact"
echo "(d) Display All Contact’s Information"
echo "(e) Exit"
echo "Your Choice?"
read choice
if [ "$choice" = "a" ]
then
./addContact.sh
elif [ "$choice" = "r" ]
then
./removeContact.sh
elif [ "$choice" = "s" ]
then
./searchContact.sh
elif [ "$choice" = "d" ]
then
./displayContact.sh
elif [ "$choice" = "e" ]
then
exit=1
else
echo "Error"
sleep 2
fi
done
exit 0
#!/bin/sh
#addContact.sh
ContactList="contacts.txt"
echo “Please input First Name:”
read nameFirst
echo “Please input Last Name:”
read nameLast
echo “Please input Phone Number:”
read number
echo “Please Input Address”
read address
echo “Please input Email:”
read email
echo $nameFirst:$nameLast:$number:$address:$email>> ContactList;
echo "A new contact is added to your book."
exit 0
sed '/'$x'/ d' ContactList
won't remove anything from the file ContactList, it will simply output the changes to standard output.
If you want to edit the file in-place, you'll need the -i flag (easy) or to make a temporary file which is then copied back over ContactList (not so easy, but needed if your sed has no in-place editing option).
In addition, since ContactList is a shell variable referencing the real file contacts.txt, you'll need to use $ContactList.
And, as a final note, since you're using the full line content to do deletion, the presence of an address like 1/15 Station St is going to royally screw up your sed command by virtue of the fact it contains the / character.
I would suggest using awk rather than sed for this task since it's much better suited to field-based data. With the record layout:
$nameFirst:$nameLast:$number:$address:$email
you could remove an entry with something like (including my patented paranoid perfect protection policy):
cp contacts.txt contacts.txt.$(date +%Y.%m.%d.%H.%M.%S_$$)
awk <contacts.txt >tmp.$$ -F: "-vF=$nameFirst" "-vL=$nameLast" '
F != $1 || L != $2 {print}'
mv tmp.$$ contacts.txt

solaris echo " [ " character problem

i have bash script such as
for i in `echo a [ matched.lines`
do
echo $i
done
why output of this script below
a
[
matched.lines
i want output text as it is
a [ matched.lines
how can i do that
thanks for help
The script echos each token seperately. Use echo -n $i inside do ... done.
i have replaced ' ' characters to '' with sed global replace and there is no new line on output of script thanks for help
to read a file using shell, use while read loop
while read -r loop
do
case "$line" in
*]* ) echo $line;;
esac
done <"file"
Sorry but that's not going to do what you want it to. Your for loop is using a space as a delimiter to it's arguments. This will cause each one of the item's to echo on a seperate line. Adding a -n doesn't work here because you will not get the \n at the end of the line. Honestly I don't see what it is your trying to do here. If you just want to echo this "a [ matched.lines" as a string you can do this:
for i in "a [ matched.lines";do
echo $i
done
But I feel you're going to misunderstand how to use a for loop....

Resources