continuing echo of two different statements back to same line - bash

I know using echo -n option , we can update the output in same line .
But i have different scenario :
echo "Currently reading file :"
if [some_condition];then
echo -n $file_read
else
echo -n "Skipping file read:" $file_skip
fi
echo "successfully completed"
Current output :
Currently reading file :
0 1 2 Skipping file read : 3 Skipping file read 4 5 6 7 8
Completed reading files successfully
Expecting output 1 :
Currently reading file :
0 1 2 .....9 10 11 ....
Skipping file read : 4 5 6 ....12 13
OR
Expecting Output 2:
for this i can use -en option for this
currently Reading file : only latest file no
Skipped these files : 1 2 9 15 21 ....
OR
Any other best way possible
Is there any better way to display this output scenario . Files range may be between 1 to 2000 .
I even tried displaying only the latest output using
echo -en "$file_read \r"
But this also wont look good when a file is skipped reading .

You can declare firstly the initial values of FIRST_ROW or SECOND_ROW as you with
For example:
SECOND_ROW="Skipping file read : "
Then you assign the outputs you need in 2 different variables for 'Expecting output 1'
if [some_condition];then
FIRST_ROW= "$FIRST_ROW $file_read"
else
SECOND_ROW= "$SECOND_ROW $file_skip"
fi
And finally you can print the desired output using
echo
and custom strings as you wish

Related

Cannot print in awk command in bash script

I am trying to read values from a file and print specific items into a variable which I will use later.
cat /dir1/file1 | while read blmbline2
do
BLMBFILE2=`print $blmbline2 | awk '{$1=""; print $0}'`
echo $BLMBFILE2
done
When I run that same code at the command line, it runs as expected, but, when I run it in a bash script called testme.sh, I get this error:
./testme.sh: line 3: print: command not found
If I run print by itself at the command prompt, I don't get an error (just a blank line).
If I run "bash" and then print at the command prompt, I get command not found.
I can't figure out what I'm doing wrong. Can someone suggest?
updated: I see some other posts that say to use echo or printf? Is there a difference I need to be concerned with in using one of those in bash?
Since awk can read files, you may be able to do away with the cat | while read and just use awk. Using a sample file containing:
1 2 3 4 5 6
1 2 3 4 5 6
1 2 3 4 5 6
1 2 3 4 5 6
1 2 3 4 5 6
1 2 3 4 5 6
Declare your bash array variable and populate with the output from awk:
arr=() ; arr=($(awk '{$1=""; print $0}' /dir1/file1))
Use the following to display array size and contents:
printf "array length: %d\narray contents: %s\n" "${#arr[#]}" "${arr[*]}"
Output:
array length: 30
array contents: 2 3 4 5 6 2 3 4 5 6 2 3 4 5 6 2 3 4 5 6 2 3 4 5 6 2 3 4 5 6
Change print to echo in your shell script. With printf you can format the data and with echo it will print the entire line of the file. Also, create an array so you can store multiple items:
BLMBFILE2=()
while IFS= read -r -d $'\0'
do
BLMBFILE2+=(`echo $REPLY | awk '{$1=""; print $0}'`)
echo $BLMBFILE2
done < <(cat /dir1/file1)
echo "Items found:"
for value in "${BLMBFILE2[#]}"
do
echo $value
done

Count checker from log file with bash script

i have the script that has output logfile.txt :
File_name1
Replay requests : 5
Replay responsee : 5
Replay completed : 5
--------------------
File_name2
Replay requests : 3
Replay responsee : 3
Replay completed : 3
--------------------
I need to check that counts at all 3 line were the same, and if one of the line mismatched move File_name to "echo".
I tried to grep with pattern file like cat logfile.txt | grep -f patternfile.ptrn with for loop, but there is no result, can`t find how to put first count in parameter that allow me to check it with next line, and how to check when there are many files_names at the logfile.
Pattern was :
Replay requests :
Replay responsee :
Replay completed :
--------------------
Its a correct idea or mb i`m moving in wrong way?
I need to check that counts at all 3 line were the same, and if one of the line mismatched move File_name to "echo".
Here is one approach/solution.
Given your input example.
File_name1
Replay requests : 5
Replay responsee : 5
Replay completed : 5
--------------------
File_name2
Replay requests : 3
Replay responsee : 3
Replay completed : 3
--------------------
The script.
#!/usr/bin/env bash
while mapfile -tn4 array && ((${#array[*]})); do
name="${array[0]}"
contents=("${array[#]:1}")
contents=("${contents[#]##* }")
for n in "${contents[#]:1}"; do
(( contents[0] != n )) &&
printf '%s\n' "$name" &&
break
done
done < <(grep -Ev '^-+$' file.txt)
It will not print anything (filename) but change just one value of count (assuming count is the last string per line which is a number) then it should print the filename.
Note that mapfile aka readarray is a bash4+ feature.
The script above assumes that there are 4 lines in between the dashes that separates the Filenames.
and how to check when there are many files_names at the logfile.
Not sure what that means. Clarify the question.
Here is a stating point for a script; I have not well understood the whole question and don't know what exact output is expected.
#! /bin/bash
declare -A dict
while read -a line ; do
test "${line[0]}" == "Replay" || continue
rep="${line[1]}"
num="${line[3]}"
if test "${dict[$rep]}" == "" ; then
dict[$rep]=$num
elif test "${dict[$rep]}" != "$num" ; then
echo "Value changed for $rep : ${dict[$rep]} -> $num"
fi
done < "logfile.txt"
If for instance the input is
File_name1
Replay requests : 5
Replay responsee : 3
Replay completed : 7
--------------------
File_name2
Replay requests : 2
Replay responsee : 3
Replay completed : 6
--------------------
the output will be :
Value changed for requests : 5 -> 2
Value changed for completed : 7 -> 6
Is it helpful?

How to split up function from arguments in bash?

I am writing a bash script named safeDel.sh with base functionalities including:
file [file1, file2, file3...]
-l
-t
-d
-m
-k
-r arg
For the single letter arguments I am using the built in function getops which works fine. The issue I'm having now is with the 'file' argument. The 'file' argument should take a list of files to be moved to a directory like this:
$ ./safeDel.sh file file1.txt file2.txt file3.txt
The following is a snippet of the start of my program :
#! /bin/bash
files=("$#")
arg="$1"
echo "arguments: $arg $files"
The echo statement shows the following:
$ arguments : file file
How can I split up the file argument from the files that have to be moved to the directory?
Assuming that the options processed by getopts have been shifted off the command line arguments list, and that a check has been done to ensure that at least two arguments remain, this code should do what is needed:
arg=$1
files=( "${#:2}" )
echo "arguments: $arg ${files[*]}"
files=( "${#:2}" ) puts all the command line arguments after the first into an array called files. See Handling positional parameters [Bash Hackers Wiki] for more information.
${files[*]} expands to the list of files in the files array inside the argument to echo. To safely expand the list in files for looping, or to pass to a command, use "${files[#]}". See Arrays [Bash Hackers Wiki].
This is a way you can achieve your needs:
#!/bin/bash
declare -a files="$#"
for fileToManage in ${files}; do
echo "Managing ... $fileToManage"
done
But it works only if there is no space in your file names, in which case you need to do some additional work.
Let me know if you need further help.
function getting_arguments {
# using windows powershell
echo #($args).GetType()
echo #($args).length
echo "#($args)[0]"
echo #($args)[0]
echo "#($args)[1..(#($args).length)]"
echo #($args)[1..(#($args).length)]
echo "debug: $(#($args)[0])" #($args)[1..(#($args).length)]
}
OUTPUT
PS C:\monkey> getting_arguments 1 2 3 4 5 6
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
6
#(1 2 3 4 5 6)[0]
1
#(1 2 3 4 5 6)[1..(#(1 2 3 4 5 6).length)]
2
3
4
5
6
debug: 1
2
3
4
5
6

I want to delete a batch from file

I have a file and contents are like :
|T1234
010000000000
02123456878
05122345600000000000000
07445678920000000000000
09000000000123000000000
10000000000000000000000
.T1234
|T798
013457829
0298365799
05600002222222222222222
09348977722220000000000
10000057000004578933333
.T798
Here one complete batch means it will start from |T and end with .T.
In the file i have 2 batches.
I want to edit this file to delete a batch for record 10(position1-2),if from position 3 till position 20 is 0 then delete the batch.
Please let me know how i can achieve this by writing a shell script or syncsort or sed or awk .
I am still a little unclear about exactly what you want, but I think I have it enough to give you an outline on a bash solution. The part I was unclear on is exactly which line contained the first two characters of 10 and remaining 0's, but it looks like that is the last line in each batch. Not knowing exactly how you wanted the batch (with the matching 10) handled, I have simply written the remaining wanted batch(es) out to a file called newbatch.txt in the current working directory.
The basic outline of the script is to read each batch into a temporary array. If during the read, the 10 and 0's match is found, it sets a flag to delete the batch. After the last line is read, it checks the flag, if set simply outputs the batch number to delete. If the flag is not set, then it writes the batch to ./newbatch.txt.
Let me know if your requirements are different, but this should be fairly close to a solution. The code is fairly well commented. If you have questions, just drop a comment.
#!/bin/bash
ifn=${1:-dat/batch.txt} # input filename
ofn=./newbatch.txt # output filename
:>"$ofn" # truncate output filename
declare -i bln=0 # batch line number
declare -i delb=0 # delete batch flag
declare -a ba # temporary batch array
[ -r "$ifn" ] || { # test input file readable
printf "error: file not readable. usage: %s filename\n" "${0//*\//}"
exit 1
}
## read each line in input file
while read -r line || test -n "$line"; do
printf " %d %s\n" $bln "$line"
ba+=( "$line" ) # add line to array
## if chars 1-2 == 10 and chars 3 on == 00...
if [ ${line:0:2} == 10 -a ${line:3} == 00000000000000000000 ]; then
delb=1 # set delete flag
fi
((bln++)) # increment line number
## if the line starts with '.'
if [ ${line:0:1} == '.' ]; then
## if the delete batch flag is set
if [ $delb -eq 1 ]; then
## do nothing (but show batch no. to delete)
printf " => deleting batch : %s\n" "${ba[0]}"
## if delb not set, then write the batch to output file
else
printf "%s\n" ${ba[#]} >> "$ofn"
fi
## reset line no., flags, and uset array.
bln=0
delb=0
unset ba
fi
done <"$ifn"
exit 0
Output (to stdout)
$ bash batchdel.sh
0 |T1234
1 010000000000
2 02123456878
3 05122345600000000000000
4 07445678920000000000000
5 09000000000123000000000
6 10000000000000000000000
7 .T1234
=> deleting batch : |T1234
0 |T798
1 013457829
2 0298365799
3 05600002222222222222222
4 09348977722220000000000
5 10000057000004578933333
6 .T798
Output (to newbatch.txt)
$ cat newbatch.txt
|T798
013457829
0298365799
05600002222222222222222
09348977722220000000000
10000057000004578933333
.T798

Concatenate output of two commands into one line

I have a very basic shell script here:
for file in Alt_moabit Book_arrival Door_flowers Leaving_laptop
do
for qp in 10 12 15 19 22 25 32 39 45 60
do
for i in 0 1
do
echo "$file\t$qp\t$i" >> psnr.txt
./command > $file-$qp-psnr.txt 2>> psnr.txt
done
done
done
command calculates some PSNR values and writes a detailed summary to a file for each combination of file, qp and i. That's fine.
The 2>> outputs one line of information that I really need. But when executed, I get:
Alt_moabit 10 0
total 47,8221 50,6329 50,1031
Alt_moabit 10 1
total 47,8408 49,9973 49,8197
Alt_moabit 12 0
total 47,0665 50,1457 49,6755
Alt_moabit 12 1
total 47,1193 49,4284 49,3476
What I want, however, is this:
Alt_moabit 10 0 total 47,8221 50,6329 50,1031
Alt_moabit 10 1 total 47,8408 49,9973 49,8197
Alt_moabit 12 0 total 47,0665 50,1457 49,6755
Alt_moabit 12 1 total 47,1193 49,4284 49,3476
How can I achieve that?
(Please feel free to change the title if you think there's a more appropriate one)
You could pass the -n option to your first echo command, so it doesn't output a newline.
As a quick demonstration, this :
echo "test : " ; echo "blah"
will get you :
test :
blah
With a newline between the two outputs.
While this, with a -n for the first echo :
echo -n "test : " ; echo "blah"
will get you the following output :
test : blah
Without any newline between the two output.
The (GNU version of) echo utility has a -n option to omit the trailing newline. Use that on your first echo. You'll probably have to put some space after the first line or before the second for readability.
You can use printf instead of echo, which is better for portability reasons.
printf is the correct way to solve your problem (+1 kurumi), but for completeness, you can also do:
echo "$file\t$qp\t$i $( ./command 2>&1 > $file-$qp-psnr.txt )" >> psnr.txt
While echo -n may work if you just want the print the output to console, it won't work if you want the output redirected to file.
If you want the concatenated output to be redirected to a file, this will work:
echo "Str1: `echo "Str2"`" >> file
I was also facing the same problem.
To define my problem, I have a script which is using the echo function like this:
echo -n "Some text here"
echo -n "Some text here"
The output I was getting is like this:
-n Some text here
-n Some text here
and I want the text to be in same line and it is also printing -n option in the output.
Note :- According to man Page, -n option do not print the trailing newline character.
The way I solved it using by adding the shebang in the starting of the script file like this.
#!/bin/bash
echo -n "Some text here"
echo -n "Some text here"
This will print the desired output like this:
Some text here Some text here
Hope this helps!

Resources