How do I use 'sed' to read a line from txt? - linux

I am trying to use a variable (the day of the year out of 365 using +%j) to search a txt file, using that variable to find the line number.
I can't figure out how to substitute '1p' below to something like.. "$dat + p" or something like that. Nothing I am thinking of or finding online is working, I am thinking I just am not coming up with good enough search terms to figure this thing out.
Here is what I have so far:
#!/usr/bin/bash
dat= date +%j
arg=$(cat /home/adam/dailyverses.txt | sed -n '1p')
echo $arg

First you need to catch the output of the date command this way:
dat="$(date +%j)"
Or this way when you need to comply with an old shell:
dat=`date "+%j"`
I am trying to use a variable (the day of the year out of 365 using +%j) to search a txt file, using that variable to find the line number.
So I think sed is not the right tool. Trying to make a substitution is not the right way.
Searching a pattern and getting the line number which match this pattern: grep would be the perfect fit! For example:
grep -nE "^.*${dat}.*$" /home/adam/dailyverses.txt|cut -d: -f1
You can also do it using bash:
line_number=1
while read -r; do
[[ $REPLY =~ ^.*${dat}.*$ ]] && echo "${line_number}"
(( line_number++ ))
done < "/home/adam/dailyverses.txt"
Or awk:
awk 'BEGIN {count = 1} {count++; if($0 ~ "^.*'"${dat}"'.*$"){print count}}' "/home/adam/dailyverses.txt"
Of course you can change the regexp according to your needs.
I can't figure out how to substitute '1p' below to something like.. "$dat + p" or something like that.
That's not really the same thing than just "find the line number" like you asked before. But if it's what's you really want:
dat="$(date +%j)"
sed -n "${dat}p" /home/adam/dailyverses.txt

Related

Bash - Extracting just the date and time from a string variable with other surrounding text being excluded

I'm new to sed and have been trying to use it with no luck yet in this case.
I'm reading through a log file and I store the prior line into a variable so that I can extract out the date if needed.
variable string example:
jcl/jclnt.log-[05/06/20 16:42:52.964]:jclnt ST:
I'm only wanting the date and timestamp in the square brackets. I want to ignore the characters before and after. The date and time format are always the same length and format. I can match on it with a regex, just not sure how to extract it from a variable into a new variable with only the data inside the square brackets.
I tried something like this:
priordate= echo "$prior" | awk -F'[][]' '{print $2}'
But that didn't work.
It should work if you remove the space before your echo.
echo "jcl/jclnt.log-[05/06/20 16:42:52.964]:jclnt ST:" | awk -F'[][]' '{print $2}'
05/06/20 16:42:52.964
and then make the statement thus: priordate=$(echo ...)
You can use Bash's native regular expression matching. This is a quick and dirty regular expression that just relies on capturing whatever is between [ and ]. You can certainly make it more specific if necessary.
#!/bin/bash
s="jcl/jclnt.log-[05/06/20 16:42:52.964]:jclnt ST:"
pattern="\[(.*)\]"
if [[ "${s}" =~ $pattern ]]
then
date_time="${BASH_REMATCH[1]}"
fi
echo "${date_time}"
Output:
05/06/20 16:42:52.964

sed not working on a variable within a bash script; requesting a file. Simple example

If I declare a variable within a bash script, and then try to operate on it with sed, I keep getting errors. I've tried with double quotes, back ticks and avoiding single quotes on my variable. Here is what I'm essentially doing.
Call my script with multiple parameters
./myScript.sh apples oranges ilike,apples,oranges,bananas
My objective is to use sed to replace $3 "," with " ", then use wc -w to count how many words are in $3.
MyScript.sh
fruits="$3"
checkFruits= sed -i 's/,/ /g' <<< "$fruits"
echo $checkFruits
And the result after running the script in the terminal:
ilike,apples,oranges,bananas
sed: no input files
P.s. After countless google searches, reading suggestions and playing with my code, I simply cannot get this easy sample of code to work and I'm not really sure why. And I can't try to implement the wc -w until I move past this block.
You can do
fruits="$3"
checkFruits="${3//,/ }"
# or
echo "${3//,/ }"
The -i flag to sed requires a file argument, without it the sed command does what you expect.
However, I'd consider using tr instead of sed for this simple replacement:
fruits="$3"
checkFruits="$(tr , ' ' <<< $fruits)"
echo $checkFruits
Looking at the larger picture, do you want to count comma-separated strings, or the number of words once you have changed commas into spaces? For instance, do you want the string "i like,apples,oranges,and bananas" to return a count of 4, or 6? (This question is moot if you are 100% sure you will never have spaces in your input data.)
If 6, then the other answers (including mine) will already work.
However, if you want the answer to be 4, then you might want to do something else, like:
fruits="$3"
checkFruits="$(tr , \\n <<< $fruits)"
itemCount="$(wc -l <<< $checkFruits)"
Of course this can be condensed a little, but just throwing out the question as to what you're really doing. When asking a question here, it's good to post your expected results along with the input data and the code you've already used to try to solve the problem.
The -i option is for inplace editing of input file, you don't need it here.
To assign a command's output to a variable, use command expansion like var=$(command).
fruits="$3"
checkFruits=$(sed 's/,/ /g' <<< "$fruits")
echo $checkFruits
You don't need sed at all.
IFS=, read -a things <<< "$3"
echo "${#things[#]}"

how to print last part of a string in shell script

I have this line:
102:20620453:d=2017021012:UGRD:10 m above ground:15 hour fcst::lon=79.500000,lat=9.000000,val=-5.35
Now I want to just print the value -5.35 from this line and nothing else.
I also want this command to be able to extract the -7.04 from this line and nothing else.
102:20620453:d=2017021012:UGRD:10 m above ground:15 hour fcst::lon=280.500000,lat=11.000000,val=-7.04
I have read the other stack overflow questions and they did not seem to quite get at what I was looking for. I noticed that they did you awk or sed. What types of things should I do to be able to extract just the part of the above lines after val=?
There's no need for awk, sed, or any other external tool: bash has its own built-in regular expression support, via the =~ operator to [[ ]], and the BASH_REMATCH array (populated with matched contents).
val_re='[, ]val=([^ ]+)'
line='102:20620453:d=2017021012:UGRD:10 m above ground:15 hour fcst::lon=79.500000,lat=9.000000,val=-5.35'
[[ $line =~ $val_re ]] && echo "${BASH_REMATCH[1]}"
That said, if you really want to remove everything up to and including the string val= (and thus to have your code break if other values were added to the format in the future), you could also do so like this:
val=${line##*val=} # assign everything from $line after the last instance of "val=" to val
The syntax here is parameter expansion. See also BashFAQ #100: How do I do string manipulations in bash?
You can use awk with field separator as = and print last field:
awk -F'=' '{print $NF}' <<< "$str"
-5.35
this will search the string val= from the end and give anything after that
str='102:20620453:d=2017021012:UGRD:10 m above ground:15 hour fcst::lon=79.500000,lat=9.000000,val=-5.35'
echo "$str" | grep -Po '(?<=val=).*'
answer works on GNU grep only

Extract just file path from string

I have a file that contains strings in this format:
MD5 (TestImages/IMG_0627.JPG) = 6ed611b3e777c5f7b729fa2f2412d656
I am trying to figure out a way to extract the file path, so that I would get a string like this:
TestImages/IMG_0627.JPG
For a different part of my script, I am using this code to remove everything before and after the brackets, and I could of course do something similar, however I'm sure there is a better way?
shortFile=${line#*MD5 }
shortFile=${shortFile%%)*}
Anyone have any suggestions?
You could use sed but that has the overhead of starting a new process.
echo $line | sed -r 's/MD5 \((.*)\).*/\1/'
Just to throw a non-sed answer onto the pile. (Also slightly cheaper since it avoids the pipeline and sub-shell.)
awk -F '[()]' '{print $2}' <<<"$line"
That said the substring expansion option is a reasonable one if it does what you need. (Though it looks like you missed the ( in the first expansion.)
Another way with cut can be :
echo $line|cut -d "(" -f2|cut -d ")" -f1
sed -e 's/^.*(\([^)]*\)).*$/\1/' < infile.txt

Line from bash command output stored in variable as string

I'm trying to find a solution to a problem analog to this one:
#command_A
A_output_Line_1
A_output_Line_2
A_output_Line_3
#command_B
B_output_Line_1
B_output_Line_2
Now I need to compare A_output_Line_2 and B_output_Line_1 and echo "Correct" if they are equal and "Not Correct" otherwise.
I guess the easiest way to do this is to copy a line of output in some variable and then after executing the two commands, simply compare the variables and echo something.
This I need to implement in a bash script and any information on how to get certain line of output stored in a variable would help me put the pieces together.
Also, it would be cool if anyone can tell me not only how to copy/store a line, but probably just a word or sequence like : line 1, bytes 4-12, stored like string in a variable.
I am not a complete beginner but also not anywhere near advanced linux bash user. Thanks to any help in advance and sorry for bad english!
An easier way might be to use diff, no?
Something like:
command_A > command_A.output
command_B > command_B.output
diff command_A.output command_B.output
This will work for comparing multiple strings.
But, since you want to know about single lines (and words in the lines) here are some pointers:
# first line of output of command_A
command_A | head -n 1
The -n 1 option says only to use the first line (default is 10 I think)
# second line of output of command_A
command_A | head -n 2 | tail -n 1
that will take the first two lines of the output of command_A and then the last of those two lines. Happy times :)
You can now store this information in a variable:
export output_A=`command_A | head -n 2 | tail -n 1`
export output_B=`command_B | head -n 1`
And then compare it:
if [ "$output_A" == "$output_B" ]; then echo 'Correct'; else echo 'Not Correct'; fi
To just get parts of a string, try looking into cut or (for more powerful stuff) sed and awk.
Also, just learing a good general purpose scripting language like python or ruby (even perl) can go a long way with this kind of problem.
Use the IFS (internal field separator) to separate on newlines and store the outputs in an array.
#!/bin/bash
IFS='
'
array_a=( $(./a.sh) )
array_b=( $(./b.sh) )
if [ "${array_a[1]}" = "${array_b[0]}" ]; then
echo "CORRECT"
else
echo "INCORRECT"
fi

Resources