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
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
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
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.
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'`
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