Replace variable in bash file using sed - output lags - linux

I'm trying to write a bash script that search and replace a specific
user input saved in config.sh using sed. This does work; however it
only works partially as shown below.
config.sh
#!/bin/bash
#
#UserName to be deleted
delUserName=""
#Source
delUserSrc=/Users/"$delUserName"
#Destination
delUserDest=/Users/John/BackUp/"$delUserName"/"$delUserName".zip
main.sh
#!/bin/bash
#
source scripts/config.sh
echo -e "\nEnter user you wish to delete: \c"
read -r UserName
sed -i '' -e "s/delUserName=.*/delUserName=$UserName/g" scripts/config.sh
echo -e "delUserName: $delUserName"
echo -e "delUserSrc: $delUserSrc"
echo -e "delUserDest: $delUserDest"
output1:
Enter user you wish to delete: Test
delUserName:
delUserSrc:/Users/
delUserDest:/Users/John/BackUp/ / .zip
output2:
Enter user you wish to delete: Test1
delUserName:Test
delUserSrc:/Users/Test
delUserDest:/Users/John/BackUp/Test/Test.zip
output3:
Enter user you wish to delete: Test1
delUserName:Test1
delUserSrc:/Users/Test1
delUserDest:/Users/John/BackUp/Test1/Test1.zip
expected output1:
Enter user you wish to delete: Test
delUserName:Test
delUserSrc:/Users/Test
delUserDest:/Users/John/BackUp/Test/Test.zip
expected output2:
Enter user you wish to delete: Test1
delUserName:Test1
delUserSrc:/Users/Test1
delUserDest:/Users/John/BackUp/Test1/Test1.zip
The script lags. sed instantaneously changed the value for $delUserName BUT The proper values for $delUserName, $delUserSrc, and $delUserDest only echo on the 2nd run. The scripts run well when all variables are in main.sh except i have to do it this way. Save the user input into $UserName. Any idea why the values don't show when run the 1st time?
Thanks

Here is what I think is happening.
The sed command replaces text in files. It does not modify the value of variables in memory. These values are assigned when you source config.sh.
So right after your sed line, you need to put this line :
source scripts/config.sh
It is the same line as above in your script. This is required there also so that your newly replaced values will be loaded in the variables so that you can display them. Once the new values are loaded in memory, then the echo statements will be able to expand the variables to that new value.

Related

BASH scripting to long list a directory using Input and standard errors

I want to create a script that will list in long form the contents of a directory. However, I want to make sure first that the user does not add input to the script command line until prompted if so I need to apply an error and exit. If it passes that test, then the script should then ensure the directory exists before attempting to list it. If it doesn't then another error out. If it exists I need to display the contents in long listing.
I'm really new at this and here is what I have so far. I'm not sure that I'm even on the right track. Any help would be appreciated.
#!/bin/bash
# File Name: dlist
# Usage: dlist prompt: [/directory/path/here]
# Synopsis: The dlist script will prompt the user to input a directory path and will
# return a long listing of the contents in that directory.
# Author: Romero
# Notify user of incoming prompt
echo -e "You will be prompted to enter the name of a directory you want to list in long form. "
# Prompt the user to input the directory to list on the same line as the input prompt
read -p "Directory to list: "
# Ensure User has not input directly into command line; if so issue std error 1 and exit
# Check to ensure directory exists before listing; if not issue std error 2 and exit
# If directory exists, list it in long form
if [ ! -d "$DIRECTORY" ]; then
echo "This directory does not exist to list!" 1>&2
exit 2
elif [ -d "$DIRECTORY" ]; then
echo ls -l "$DIRECTORY"
fi
Use the Bash variable $# to get the number of arguments. See here for an example.

How do you append a string built with interpolation of vars and STDIN to a file?

Can someone fix this for me.
It should copy a version log file to backup after moving to a repo directory
Then it automatically appends line given as input to the log file with some formatting.
That's it.
Assume existence of log file and test directory.
#!/bin/bash
cd ~/Git/test
cp versionlog.MD .versionlog.MD.old
LOGDATE="$(date --utc +%m-%d-%Y)"
read -p "MSG > " VHMSG |
VHENTRY="- **${LOGDATE}** | ${VHMSG}"
cat ${VHENTRY} >> versionlog.MD
shell output
virufac#box:~/Git/test$ ~/.logvh.sh
MSG > testing script
EOF
EOL]
EOL
e
E
CTRL + C to get out of stuck in reading lines of input
virufac#box:~/Git/test$ cat versionlog.MD
directly outputs the markdown
# Version Log
## version 0.0.1 established 01-22-2020
*Working Towards Working Mission 1 Demo in 0.1 *
- **01-22-2020** | discovered faker.Faker and deprecated old namelessgen
EOF
EOL]
EOL
e
E
I finally got it to save the damned input lines to the file instead of just echoing the command I wanted to enter on the screen and not executing it. But... why isn't it adding the lines built from the VHENTRY variable... and why doesn't it stop reading after one line sometimes and this time not. You could see I was trying to do something to tell it to stop reading the input.
After some realizing a thing I had done in the script was by accident... I tried to fix it and saw that the | at the end of the read command was seemingly the only reason the script did any of what it did save to the file in the first place.
I would have done this in python3 if I had know this script wouldn't be the simplest thing I had ever done. Now I just have to know how you do it after all the time spent on it so that I can remember never to think a shell script will save time again.
Use printf to write a string to a file. cat tries to read from a file named in the argument list. And when the argument is - it means to read from standard input until EOF. So your script is hanging because it's waiting for you to type all the input.
Don't put quotes around the path when it starts with ~, as the quotes make it a literal instead of expanding to the home directory.
Get rid of | at the end of the read line. read doesn't write anything to stdout, so there's nothing to pipe to the following command.
There isn't really any need for the VHENTRY variable, you can do that formatting in the printf argument.
#!/bin/bash
cd ~/Git/test
cp versionlog.MD .versionlog.MD.old
LOGDATE="$(date --utc +%m-%d-%Y)"
read -p "MSG > " VHMSG
printf -- '- **%s** | %s\n' "${LOGDATE}" "$VHMSG" >> versionlog.MD

Assign full text file path to a variable and use variable as file path in sh file

I am trying to create a shell script for logs and trying to append data into a text file. I have write this sample "test.sh" code for testing:
#!/bin/sh -e
touch /home/sample.txt
SPTH = '/home/sample'.txt
echo "MY LOG FILE" >> "$SPTH"
echo "DUMP started at $(date +'%d-%m-%Y %H:%M:%S')" >> /home/sample.txt
echo "DUMP finished at $(date +'%d-%m-%Y %H:%M:%S')" >> /home/sample.txt
but in above code all lines are working correct except one line of code i.e.
echo "MY LOG FILE" >> "$SPTH"
It is giving error:
test.sh: line 6: : No such file or directory
I want to replace this full path of file "/home/sample.txt" to variable "$SPATH".
I am executing my shell script using
sh test.sh
What I am doing wrong.
Variable assignments in bash shell does not allow you to have spaces within. It will be actually interpreted as command with = and the subsequent keywords as arguments to the first word, which is wrong.
Change your code to
SPTH="/home/sample.txt"
That is the reason why SPTH was not assigned to the actual path you intended it to have. And you have no reason to have single-quote here and excluding the extension part. Using it fully within double-quotes is absolutely fine.
The syntax for the command line is that the first token is a command, tokens are separated by whitespace. So:
SPTH = '/home/sample'.txt
Has the command as SPTH, the second token is =, and so on. You might think this is daft, but most shells behave like this for historical reasons.
So you need to remove the whitespace:
SPTH='/home/sample'.txt

Pass content from .txt file as argument for bash script?

I need to "Write a script to add users to your system in which the names of the users are given to script as an argument n (in?, spell error by professor) a text file of the format
Last_Name First_Name Middle_Initial Group
(rest of instructions FYI) Your script should create unique user names of up to 8 characters, and generate
random passwords for the users. The users should be assigned home directories
depending on the group they are in. You can assume that the users will belong to
Management (“mgmt”), Employee (“empl”) or Temporary (“temp”) and that their
respective directories are under these group names in /home. For e.g., if John Doe is
in “mgmt.”, and his user name is jdoe1234, then his home directory should be in
/home/mgmt/jdoe1234. Lock the home directories such that no one else has
permissions to the home directories than the users themselves.
Your script should generate a file called users.txt that contains the following columns:
Last Name First Name UID Password
which can be used to distribute the user names and passwords to the users.
The first part (not in italics) is what confuses me. If I understand his wording correctly, he wants me to take text from a separate .txt file and use it as the arguments for my script? With the idea of
./file.sh arg1 arg2 arg3 arg4
except those args are going to be the first four words in the .txt file? Say, if the .txt file contains "Doe John A empl", then it would be like typing
./file.sh arg1 arg2 arg3 arg4
Here's my attempt so far (I've actually tried other things but this is what I have on screen right now, sort of what I started out with):
#!/bin/bash
echo "$(cat file.txt)"
lname=$(echo $1|head -c 3)//to make username use first 3 letters of last name
fname=$(echo $2|head -c 1)//to make username use first letter of first name
mname=$3
group=$4
echo "$lname$fname$mname$group"
As of right now, anything below the first line doesn't do anything. I got the first line from command line arguments from a file content and I used it because I thought it would let me use the content from a .txt file as arguments but it's clearly not doing that. It's just outputting the content of it, not using letting me using each word as an argument. Not sure what to do. Any help? I thought this wasn't going to be very difficult as I started writing the script assuming the user would provide the arguments but I reread the first part of the instructions and assume he wants them to be taken from a separate .txt file.
$(command) returns the output of the command. If you do $(cat some_file) it will return the text of the file. You can use it to give the content of a file as an argument doing:
cmd1 $(cat args_file)
So when you use echo $(cat file.txt), you get the same output as if you were using cat file.txt because cat sends the content of the file to echo which displays it to the standard output.
$n means argument n passed to the script ($0 being the name of the script). Here you simply have to provide one argument, the name of the file. So $2, $3 and $4 will not contain anything.
So, from the file you can only get a string with the names with $names=$(cat $1). In order to get each field separately, you can use cut:
lname=$(cut -d \ -f 1 $1)
fname=$(cut -d \ -f 2 $1)
mname=$(cut -d \ -f 3 $1)
group=$(cut -d \ -f 4 $1)
NOTES:
The symbol for comments in shell is # NOT //.
head displays the first lines of a file, head -c the first bytes. It does not cut the file.
What I understood as the problem is that:
Firstly: You want to pass the contents of a text file as an input/argument to a shell script.
There could be other ways, but I suggest the following:
./YourScriptFile.sh $(cat YourInputFile.txt)
Secondly: You want to use its contents.
I would suggest to use the following inside your script file:
$1, $3, $4, ..., $n
to access the:
1st, 2nd, 3rd, ..., nth
tokens from the input file (irrespective of new lines).
Finally: You want to make username use first 3 letters of last name or in other words you want to extract characters from a string.
Once you have tokens it's just simple. I would suggest the following:
FirstTwoChars_of_FirstToken=${1:0:2}
FirstTwoChars_of_SeventhToken=${7:0:2}
Or
LastTwoChars_of_FirstToken=${1:7:9}
# if the first token is "FirstName" it would return you "me"
Hope this would help you to improve your code.
As a footnote: Your code will become: (# is used for comments here)
#!/bin/bash
lname=$(1:0:3) #to make username use first 3 letters of last name
fname=$(2:0:1) #to make username use first letter of first name
mname=$3
group=$4
echo "$lname$fname$mname$group"
Now you will have to execute your shell script as mentioned above.

Echo text that is user-editable

Is it possible to output text to a shell window, via bash script, that is user-editable? I essentially want to pre-fill certain information and give the user the ability to edit it if it's wrong.
For instance, if I were to write in a script:
echo -n "Enter your name: Anthony"
while read user_input
do
# do stuff with $user_input
done
How can I allow the user to inline edit the word Anthony only (aka, don't allow backspacing past the A in Anthony), and how can I store the value into a variable once the RETURN key is pressed?
EDIT
I'm looking for something similar to the -i option of read (see answer posted here), but this is only available on bash 4+. Is there an alternative for bash 3?
I needed similar setup recently so what I did was
$ cat a.sh
function input {
python -c '
import sys,readline
readline.set_startup_hook(lambda: readline.insert_text(sys.argv[2]))
sys.stderr.write(raw_input(sys.argv[1]))
' "$#" 3>&1 1>&2 2>&3
}
A=$( input 'question: ' default )
echo "A='$A'"
$ ./a.sh
question: default
A='default'
Well, it's not actually bash, but it made the job done.

Resources