Is it possible to put a pipeline in a variable - linux

I have a long pipeline that I'm constantly reusing in my script, and to make it easy to read I want to put the pipeline in a variable. Is it possible?
cat miami.tmp | grep -A5 "$date" | grep -A3 "$nexthour" | grep "celsius" | grep -E -o '[-]?[0-9].[0-9]' | head -n 1 >> miami.txt
I have tried
temperature=$( | grep -A5 "$date" | grep -A3 "$nexthour" | grep "celsius" | grep -E -
o '[-]?[0-9].[0-9]' | head -n 1 )
or
temperature="| grep -A5 "$date" | grep -A3 "$nexthour" | grep "celsius" | grep -E -o '[-]?[0-9].[0-9]' | head -n 1"
but get errors saying the commands weren't found.

This is a good case for using bash's shell functions. You can define a function like this:
function temperature() { grep foo | grep bar | grep baz; }
just make sure that the last command ends with a semicolon. You call the function with
cat file.tmp | temperature
Functions can also have parameters, accessed with the usual $1, $2 etc. notation, that can be passed in (space-separated) to the function.
$ function hello() { echo "Hello $1!"; }
$ hello world
Hello world!

You should put it in a function.
temperature () {
grep -A5 "$date" |
grep -A3 "$nexthour" |
grep "celsius" |
grep -E -o '[-]?[0-9].[0-9]' |
head -n 1
}
Maybe you want to make the date and the hour into parameters.
temperature () {
grep -A5 "$1" |
grep -A3 "$2" |
grep "celsius" |
grep -E -o '[-]?[0-9].[0-9]' |
head -n 1
}
Separately, this looks like it desperately wants to be refactored to Awk.
temperature () {
awk -v date="$1" nexthour="$2" '
$0 ~ date { p=5 }
p && p-- && ($0 ~ nexthour) { p=3 }
p && p-- && /celsius/ { n = split($0, a, /[^-.0-9]/, a);
for(i=1; i<=n; ++i) if (a[i] ~ /^-?[0-9]\.[0-9]$/)
{ print(a[i]); exit }'
}
(Untested, as you don't supply test data. I had to guess some things. If you are calling it by systematically looping over dates and hours, probably refactor that into the Awk script, too.)
Usage:
temperature 2022-11-24 04 <miami.tmp >>miami.txt
Probably see also https://mywiki.wooledge.org/BashFAQ/050

Related

Searching a specific file system in bash

I have a task which asks to write a script which displays all partitions formatted with a specific file system, given as parameter.
I have written the script but when i run it it displays '0'. What am i doing wrong?
This is my code:
#!/bin/bash
n=sudo parted -l | tail -n +8 | awk '{print $5}' | wc | awk '{print $2}'
m=sudo parted -l | tail -n +8 | awk '{print $5}'
q=sudo parted -l | tail -n +8
for i in $n; do
if [ "[ $m | sed -n ip ]" = "$1" ]; then
echo "$q | sed -n ip"
fi
done
Different approach from yours, but does it do what you need?
lsblk -f | awk '$0 ~ fs {print $NF}' fs=ext2

Bash: number of children in cron?

The sample should look if another instance of itself is already running. I do not like a pid-file solution.
Why is n=2 if I start in the console and n=3 if I let cron do it?
#!/bin/bash
count ()
{
ps aux | grep -v grep | grep -v tail | grep $0 | wc -l
}
n=$(count)
echo "`date` n=$n" >> /root/test.log

Shell command with operator followed by pipes

I want a one line command to grab the most recent restart date from JBoss restart logs. I'm currently using the following, which works
ls -rt $JBOSS_HOME/log/ser* |
xargs grep -ih "Incomplete\s*Deploy" |
awk '{print $1" "$2}' | tail -n 1
Now, I want to add an echo if the grep fails to match anything, i.e.:
ls -rt $JBOSS_HOME/log/ser* |
xargs grep -ih "Incomplete\s*Deploy" ||
echo 'NO RESTART' |
awk '{print $1" "$2}' |
tail -n 1
The problem here is that it seems that the OR operator now causes anything following to go with the failed case. How do I specify that I want to OR (echo) to be printed only when the grep fails? When the grep succeeds it should work like the first command I posted.
Use { to group the terms:
ls -rt $JBOSS_HOME/log/ser* |
xargs grep -ih "Incomplete\s*Deploy" && {
awk '{print $1" "$2}' |
tail -n 1
} ||
echo 'NO RESTART'
or as one line:
ls -rt $JBOSS_HOME/log/ser* | xargs grep -ih "Incomplete\s*Deploy" && { awk '{print $1" "$2}' | tail -n 1; } || echo 'NO RESTART'
No additional subshell required.
You can group commands within a pipe by using parentheses:
ls -rt $JBOSS_HOME/log/ser* | ( xargs grep -ih "Incomplete\s*Deploy" || echo 'NO RESTART' ) | awk '{print $1" "$2}' | tail -n 1
This makes the commands in the parentheses run in a subshell, which from the standpoint of the pipe, makes them work as a single command, i.e. they'll take the input and either print the grep match or 'NO RESTART', and then that will be fed into awk.
res=$(ls -rt $JBOSS_HOME/log/ser* | xargs grep -ih "Incomplete\s*Deploy" | awk '{print $1" "$2}' | tail -n 1)
echo "${res:-NO RESTART}"
Also note that this is not safe for filenames with spaces/etc.

Use result of pipeline as argument for another command

I'm trying to make part of the output of the first command as another command's argument.
Output of first command is like this, and 3000 is what I want:
XXXXXXXXXXXXX
abcdefg 1020 10:30
[1000] 3000
I extract the pattern by ./command1 | grep '^\[' | awk 'print $2', so it will print out 3000, the value I want.
I'd like to make 3000 as an argument of command2 ./command2 3000. How do I make this work?
command2 $( command1 | awk '/\[/{ print $2 }' )
You can use xargs to pass the input to a new command. In your example you need to include curly braces in your awk argument as well.
./command1 | grep '^\[' | awk '{ print $2 } ' | xargs ./command2
Or more concisely
.command1 | awk '/^\[/ { print $2 }' | xargs ./command2
Example:
echo "[1000] 3000" | awk '/^\[/ { print $2 }' | xargs echo
Output:
3000
There's also sed:
./command1 | sed -n 'n;n;p' | awk '{print $2}'
All together now:
./command2 $(./command1 | sed -n 'n;n;p' | awk '{print $2}') # ./command2 3000
sed will skip 2 lines and print the third.
I would personally try backticks first:
./command2 `./command1 | grep '^\[' | awk 'print $2'`

How to sleep for 1 second between each xargs command?

For example, if I execute
ps aux | awk '{print $1}' | xargs -I {} echo {}
I want to let the shell sleep for 1 second between each echo.
How can I change my shell command?
You can use the following syntax:
ps aux | awk '{print $1}' | xargs -I % sh -c '{ echo %; sleep 1; }'
Be careful with spaces and semicolons though. After every command in between brackets, semicolon is required (even after the last one).
Replace echo by some shell script named sleepecho containing
#!/bin/sh
sleep 1
echo $*
If your awk supports it:
ps aux | awk '{ system("sleep 1"); print $1 }' | xargs -I {} echo {}q
or skip awk and xargs altogether
ps aux | while read -r user rest;
echo $user
sleep 1;
done

Resources