Linux Bash Trying to write checklist progress "bar" of sorts. Replace the same line - linux

Sorry if I am not giving you enough info, this is my first time posting here.
I am trying to make this in a bash script.
Downloading...............
"run bash commands and when they are done, replace the "Downloading..." text with the text bellow in the same line aka space."
Downloading............... DONE!
go to next line and show
Installing................
"run bash commands again and when they are done, replace the "Installing..." text with the text bellow in the same line aka space."
Installing................ DONE!
I hope you get what I mean. Thanks in advance.
I've tried:
#/bin/bash
tput sc # save cursor
printf "Something that I made up for this string"
sleep 1
tput rc;tput el # rc = restore cursor, el = erase to end of line
printf "Another message for testing"
sleep 1
tput rc;tput el
printf "Yet another one"
sleep 1
tput rc;tput el
But it doesn't make new lines, it just uses one line to show all text.

I'm assuming you pulled the tput code from somewhere, and I'm guessing that 'somewhere' also explained that tput is being used to overwrite the same line multiple times (as your script actually does).
From your description it doesn't sound like you need to overwrite any lines so using tput is the wrong solution.
If I understand your description correctly you should be able to do everything you want with some (relatively) simple printf commands, eg:
printf "Downloading .... " # no '\n' in the output so cursor remains at end of current line
# run your bash commands here
printf "DONE!\n" # append to end of current line and then add a new line (\n)
printf "Installing .... " # no '\n' in the output so cursor remains at end of current line
# run more bash commands here
printf "DONE!\n" # append to end of the current line and then add a new line (\n)
Keep in mind that if any of your 'bash commands' generate any output then the cursor will be moved (probably to a new line) thus messing up your output. Net result is that you'll need to make sure your 'bash commands' do not generate any output to stdout/stderr (alternatively, make sure all output - stdout/stderr - is redirected to files).
If your requirement is to have the 'bash commands' send output to the terminal then you may need to go back to using tput ... but that's going to depend on exactly how you want the output to appear.
NOTE: If this (above) does not meet your requirement then please update the question with more details.

Related

How do I pass ">>" or "<<" to my script without the terminal trying to interpret it as me either appending to something or getting stdin?

My python script can take a series of bitwise operators as one of its arguments. They all work fine except for "=<<" which is roll left, and "=>>" which is roll right. I run my script like ./script.py -b +4,-4,=>>10,=<<1, where anything after -b can be any combination of similar operations. As soon as the terminal sees "<<" though, it just drops the cursor to a new line after the command and asks for more input instead of running the script. When it sees ">>", my script doesn't process the arguments correctly. I know it's because bash uses these characters for a specific purpose, but I'd like to get around it while still using "=>>" and "=<<" in my arguments for my script. Is there any way to do it without enclosing the argument in quotation marks?
Thank you for your help.
You should enclose the parameters that contain special symbols into single quotation marks (here, echo represents your script):
> echo '+4,-4,=>>10,=<<1'
+4,-4,=>>10,=<<1
Alternatively, save the parameters to a file (say, params.txt) and read them from the file onto the command line using the backticks:
> echo `cat params.txt`
+4,-4,=>>10,=<<1
Lastly, you can escape some offending symbols:
> echo +4,-4,=\>\>10,=\<\<1
+4,-4,=>>10,=<<1

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

Shell Script Edit Files Line

I am not that good on linux shell script and I need little help.
I want to edit a file via script (finding the line and edit).
The Original line is:
# JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=< hostname >"
I want to uncomment and replaye hostname with 127.0.0.1
JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=127.0.0.1"
You can refer to the set command, change the filename with the name you are working at,
sed -i 's## JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=< hostname >"#JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=127.0.0.1"#' filename
Fine answers, but they don't do anything by way of TEACHING the gentleman how and why it works.
If you were using the mundane text editor, ed, you would use three commands after invoking the command "ed filename":
s/^# //
s/< hostname>/127.0.0.1/
w
So, you can use a pipe to submit those commands directly to ed, specifying "-" as its first argument so that it doesn't bother you by reporting character counts upon reading in and writing out the file:
( echo 's/^# //'; echo 's//127.0.0.1/'; echo w ) | ed - filename
You don't need to echo 'q' also because ed will automatically quit when it runs out of input or encounters "end of file" (you can simulate this on the keyboard by just hitting the CTRL-D key rather than actually typing q ).
Here's one way to do it:
sed -i -e 's/# \(JVM_OPTS=.*=\).*/\1127.0.0.1"/' path/to/file
That is, replace the line with the text captured within the group \(JVM_OPTS=.*=\), so everything from JVM_OPTS= until another = sign, and append 127.0.0.1" to the end.
If there might be other lines in the file starting with # JVM_OPTS=,
then you could make the pattern matching more strict, for example:
sed -i -e 's/# \(JVM_OPTS="$JVM_OPTS -Djava.rmi.server.hostname=\).*/\1127.0.0.1"/' path/to/file

How to show line number when executing bash script

I have a test script which has a lot of commands and will generate lots of output, I use set -x or set -v and set -e, so the script would stop when error occurs. However, it's still rather difficult for me to locate which line did the execution stop in order to locate the problem.
Is there a method which can output the line number of the script before each line is executed?
Or output the line number before the command exhibition generated by set -x?
Or any method which can deal with my script line location problem would be a great help.
Thanks.
You mention that you're already using -x. The variable PS4 denotes the value is the prompt printed before the command line is echoed when the -x option is set and defaults to : followed by space.
You can change PS4 to emit the LINENO (The line number in the script or shell function currently executing).
For example, if your script reads:
$ cat script
foo=10
echo ${foo}
echo $((2 + 2))
Executing it thus would print line numbers:
$ PS4='Line ${LINENO}: ' bash -x script
Line 1: foo=10
Line 2: echo 10
10
Line 3: echo 4
4
http://wiki.bash-hackers.org/scripting/debuggingtips gives the ultimate PS4 that would output everything you will possibly need for tracing:
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
In Bash, $LINENO contains the line number where the script currently executing.
If you need to know the line number where the function was called, try $BASH_LINENO. Note that this variable is an array.
For example:
#!/bin/bash
function log() {
echo "LINENO: ${LINENO}"
echo "BASH_LINENO: ${BASH_LINENO[*]}"
}
function foo() {
log "$#"
}
foo "$#"
See here for details of Bash variables.
PS4 with value $LINENO is what you need,
E.g. Following script (myScript.sh):
#!/bin/bash -xv
PS4='${LINENO}: '
echo "Hello"
echo "World"
Output would be:
./myScript.sh
+echo Hello
3 : Hello
+echo World
4 : World
Workaround for shells without LINENO
In a fairly sophisticated script I wouldn't like to see all line numbers; rather I would like to be in control of the output.
Define a function
echo_line_no () {
grep -n "$1" $0 | sed "s/echo_line_no//"
# grep the line(s) containing input $1 with line numbers
# replace the function name with nothing
} # echo_line_no
Use it with quotes like
echo_line_no "this is a simple comment with a line number"
Output is
16 "this is a simple comment with a line number"
if the number of this line in the source file is 16.
This basically answers the question How to show line number when executing bash script for users of ash or other shells without LINENO.
Anything more to add?
Sure. Why do you need this? How do you work with this? What can you do with this? Is this simple approach really sufficient or useful? Why do you want to tinker with this at all?
Want to know more? Read reflections on debugging
Simple (but powerful) solution: Place echo around the code you think that causes the problem and move the echo line by line until the messages does not appear anymore on screen - because the script has stop because of an error before.
Even more powerful solution: Install bashdb the bash debugger and debug the script line by line
If you're using $LINENO within a function, it will cache the first occurrence. Instead use ${BASH_LINENO[0]}

Can I write a script in the command line which iterates though all files in a dir?

I would usually write a script for the following command but this time I only want to use it once and therefore would like to write it in the command line.
The script processes all files in a dir.
for FILE in *.tif # grab all the tif files
do
NEWFILE=test/${FILE} # create the new file name
gdal_translate -a_srs EPSG:25832 $FILE $NEWFILE
done
sorry...I forgot to mention that I did try "
for FILE in *.tif do NEWFILE = test_${FILE} gdal_translate -outsize 50% 50% %FILE %NEWFILE done"
..but it freezes with a > on the next line...as though it is waiting for something else.
There is basically no difference between an interactive command and a script. If you want to put your commands on one line, separate them with semicolons instead of line breaks.
for f in *.tif; do gdal_translate -a_srs EPSG:25832 $f test/$f; done
The secondary prompt is displayed by the shell if your command was not yet complete, such as if you are in the middle of a quoted string or a compound command, or if the previous line ended in a backslash.
You need semicolons between your script lines. Try
for FILE in *.tif; do NEWFILE=test/${FILE}; gdal_translate -a_srs EPSG:25832 $FILE $NEWFILE; done

Resources