Bash Using variable names in sed to insert record - bash

I'm trying to use sed in bash shell to insert a new row before row 1 with : as the Field Separator into an existing file but when I do it, it's printing the variable names instead of the values. Here's what I have. Sed seems to have quirky issues with variable names. Any suggestions?
#!/bin/bash
select CHOICE in add remove list find exit
do
echo "Pick a directory option: "
case $CHOICE in
add)
printf "What is the first name? "
read first
printf "What is the last name? "
read last
printf "What is the street address? "
read address
printf "What is the city? "
read city
printf "What is the State abreviation? "
read state
printf "What is the zip code? "
read zip
printf "What is the phone number? "
read phone
cat listing.txt | sed '1 i\ > "$first" ":" "$last" ":" "$address" ":" "$city" ":" "$state" ":" "$zip" ":" "$phone"' listing.txt;;
esac
done

I assume you're trying to edit listing.txt in place? Instead of the line starting cat listing.txt..., use this:
sed -i.bak "
1 i\\
$first : $last : $address : $city : $state : $zip : $phone
" listing.txt
This assumes that you didn't actually want quotes in the listing.txt file. It will also leave a listing.txt.bak as a backup to the edited file.

Related

BASH - Print new entry to file with line number included

I can't figure out how to add a line to a file then print that line only with the line number. Here is my current code which prints all lines:
printf "Would you like to add an entry to the file? Type yes or y? "
read addline
input=$addline
if [ $input = 'yes' ] || [ $input = 'y' ]
then
printf "Please enter a new name: First Last: "
read newname
printf "Please enter a new telephone number: xxx-xxx-xxxx: "
read phone
printf "Please enter a street address only: xxx Example Street: "
read street
printf "Please enter your birthdate: xx-xx-xxxx: "
read birth
printf "Please enter salary: xxxxxxx: "
read salary
echo -e "$newname:$phone:$street:$birth:$salary" >> datafile.txt
else
printf "\nYou did not type yes or y. Run the program again.\n"
exit
fi
printf "\nYour entry has been saved.\n"
sort -k2 $file | nl
You can use the -n option to grep to print a matching line along with its line number.
grep -n -F -x "$newname:$phone:$street:$birth:$salary" datafile.txt
Thanks to help from Barmar, I figured out my answer.
cat -n $file | grep "$newname:$phone:$street:$birth:$salary"
Thanks everyone.

use awk variable in bash script

I have a txt file with blow format:
66.57.21 - john
88.43.23 - albert
10.10.11 - smith
I wanna to execute "connect.py 66.57.21 john" for each line and I wrote this bash script:
#!/bin/bash
while read LINE; do
awk -v number = "$LINE" '$1'
awk -v name = "$LINE" '$3'
connect.py $name $number
done < "$1"
but the bash script didn't work
What is the problem
#!/usr/bin/env bash
while read -r number _ name; do
connect.py "$name" "$number"
done < "$1"
If you are wanting to use awk, here is one way to do it:
awk -F" " '{system("connect.py " $3 " " $1)}' input.txt
The -F" " splits each line of input on spaces
$1 is the first word in the array (number in the original question)
$3 is he third word in the array (name in the original question)
wrapping "connect.py " $3 " " $1 in system() causes the shell to execute the command after the substitutions have been made
ie: connect.py john 66.57.21

If statement matching words separated by special char

I'm new to unix. I have a file with an unknown amount of lines in format: "password, username" and I'm trying to make a function that checks this file against user inputted login.
What I have so far:
Accounts file format:
AAA###, firstname.lastname
echo "Please enter Username:"
read username
if cut -d "," -f2 accounts | grep -w -q $username
then
echo "Success"
fi
This function will return Success for inputs "firstname" "lastname" and "firstname.lastname" when I only want it to return for "firstname.lastname"
Any help would be appreciated.
You could go for an exact match, with ^ and $ anchors, like this:
echo "Please enter Username:"
read username
if cut -d "," -f2 accounts | grep -q "^$username$"; then
echo "Success"
fi
While this would work even when the user gives an empty input, you might want to explicitly check for that.
If you loop over the file within the shell, you can use string equality operators instead of regular expressions:
read -rp "enter Username (first.last): " username
shopt -s extglob
found=false
while IFS=, read -r pass uname _othertext; do
# from your question, it looks like the separator is "comma space"
# so we'll remove leading whitespace from the $uname
if [[ "$username" = "${uname##+([[:blank:]])}" ]]; then
echo "Success"
found=true
break
fi
done < accounts
if ! $found; then
echo "$username not found in accounts file"
fi
while read loops in the shell are very slow compared to grep, but depending on the size of the accounts file you may not notice.
Based on your comment, the issue is that the field separator is a comma then a space, not just a comma. cut can't do multi-character delimiters, but awk can. In your code, replace
cut -d "," -f2
with
awk -F ", " '{print $2}'
By the way, there are a few things needed to guard against user input:
# Use "-r" to avoid backslash escapes.
read -rp "Please enter Username:" username
# Always quote variables ("$username").
# Use "grep -F" for fixed-string mode.
# Use "--" to prevent arguments being interpreted as options.
if awk -F ", " '{print $2}' accounts | grep -wqF -- "$username"; then
echo "Success"
fi

shell bash - How to split a string acoring to a delimeter and echo each substring to a file [duplicate]

This question already has answers here:
How do I split a string on a delimiter in Bash?
(37 answers)
Closed 9 years ago.
Hi I am trying to split a string am getting from a file, using the delimiter "<" I then want to echo each string to a file. I am sort of there, but am not sure how to best split the string and then loop echo each substring (there may be up to 10 substrings) I am guessing I need to create an array to store these strings and then have a loop to echo each value?
Here is what I have so far:
while read line
do
# ceck if the line begins with client_values=
if[["$line" == *client_values=*]]
CLIENT_VALUES = 'echo "${line}" | cut -d'=' -f 2'
#Now need to split the CLIENT_VALUES using "<" as a delimeter.
# for each substring
echo "Output" >> ${FILE}
echo "Value $substring" >> ${FILE}
echo "End" >> ${FILE}
done < ${PROP_FILE}
grep '^client_values=' < "${PROP_FILE}" | while IFS='=' read name value
do
IFS='<' read -ra parts <<< "$value"
for part in "${parts[#]}"
do
echo "Output"
echo "Value $part"
echo "End"
done >> "${FILE}"
done
One line awk might be simpler here (and you get the added bonus of having the angry face regex separator =<)
$ awk -F "[=<]" '/^client_values/ { print "Output"; for (i = 2; i <= NF; i++) print "Value " $i; print "End"}' input.txt >> output.txt
$ cat input.txt
client_values=firstvalue1<secondvalue2<thirdvalue3
some text
client_values=someothervalue1<someothervalue2
$ cat output.txt
Output
Value firstvalue1
Value secondvalue2
Value thirdvalue3
End
Output
Value someothervalue1
Value someothervalue2
End
Your answer could probably also work, I think with minimal modification, you would want something like
#!/bin/bash
PROP_FILE='input.txt'
FILE="output2.txt"
while read line
do
# ceck if the line begins with client_values=
if [[ "$line" == "client_values="* ]]
then
CLIENT_VALUES=`echo "${line}" | cut -d'=' -f 2`
IFS='<' read -ra CLIENT_VALUES <<< "$CLIENT_VALUES"
for substring in "${CLIENT_VALUES[#]}"; do
echo "Output" >> "${FILE}"
echo "Value $substring" >> "${FILE}"
echo "End" >> "${FILE}"
done
fi
done < "${PROP_FILE}"
Which produces
$ cat output2.txt
Output
Value firstvalue1
End
Output
Value secondvalue2
End
Output
Value thirdvalue3
End
Output
Value someothervalue1
End
Output
Value someothervalue2
End
Though again, not sure if that's what you want or not.

How to get output of grep in single line in shell script?

Here is a script which reads words from the file replaced.txt and displays the output each word in each line, But I want to display all the outputs in a single line.
#!/bin/sh
echo
echo "Enter the word to be translated"
read a
IFS=" " # Set the field separator
set $a # Breaks the string into $1, $2, ...
for a # a for loop by default loop through $1, $2, ...
do
{
b= grep "$a" replaced.txt | cut -f 2 -d" "
}
done
Content of "replaced.txt" file is given below:
hllo HELLO
m AM
rshbh RISHABH
jn JAIN
hw HOW
ws WAS
ur YOUR
dy DAY
This question can't be appropriate to what I asked, I just need the help to put output of the script in a single line.
Your entire script can be replaced by:
#!/bin/bash
echo
read -r -p "Enter the words to be translated: " a
echo $(printf "%s\n" $a | grep -Ff - replaced.txt | cut -f 2 -d ' ')
No need for a loop.
The echo with an unquoted argument removes embedded newlines and replaces each sequence of multiple spaces and/or tabs with one space.
One hackish-but-simple way to remove trailing newlines from the output of a command is to wrap it in printf %s "$(...) ". That is, you can change this:
b= grep "$a" replaced.txt | cut -f 2 -d" "
to this:
printf %s "$(grep "$a" replaced.txt | cut -f 2 -d" ") "
and add an echo command after the loop completes.
The $(...) notation sets up a "command substitution": the command grep "$a" replaced.txt | cut -f 2 -d" " is run in a subshell, and its output, minus any trailing newlines, is substituted into the argument-list. So, for example, if the command outputs DAY, then the above is equivalent to this:
printf %s "DAY "
(The printf %s ... notation is equivalent to echo -n ... — it outputs a string without adding a trailing newline — except that its behavior is more portably consistent, and it won't misbehave if the string you want to print happens to start with -n or -e or whatnot.)
You can also use
awk 'BEGIN { OFS=": "; ORS=" "; } NF >= 2 { print $2; }'
in a pipe after the cut.

Resources