How to `rm` files as awk action? - bash

This one-liner:
sudo df /tmp \
| grep '/tmp' \
| expand - \
| cut -d " " -f 12 \
| sed 's/%//' \
| awk '{ if ($1<50)
$("sudo rm -rf /path/to/trash/files/*")
}'
seems to have no effect, while this:
sudo df /tmp \
| grep '/tmp' \
| expand - \
| cut -d " " -f 12 \
| sed 's/%//' \
| awk '{ if ($1<50)
print $1
}'
prints the percentage of disk used for tmp.
(The end goal is to flip the comparison around to ($1>50), but for testing I'm trying <.)

You don't really need so many commands in pipeline with awk.
You can just use:
df /tmp | awk 'NR>1 && $5+0 > 50 {system ("date")}'
Here change date command to something else that you need to run there.

Related

How to pass parameters to a command in bash when run line by line?

I have a file of parameters which I want to feed into a command in bash. Please note that I write the command below but the question isn't about the command, it's about how to pass the parameters from this file into the command.
The file, myfile.txt, looks like this:
3 rs523534 62297313 63097313
4 rs6365365 375800230 376600230
8 rs75466 63683994 64483994
I have a script to read each line and feed it into a command:
while read -r line; do
plink --bfile mydata \
--chr echo $line | awk '{print $1}' \
--from-bp echo $line | awk '{print $3}' \
--to-bp echo $line | awk '{print $4}' \
--r2 \
--ld-snp echo $line | awk '{print $2}' \
--ld-window-kb 100000000 \
--ld-window 100000000 \
--ld-window-r2 0 \
--out echo "processing/5_locuszoom/$line" | sed 's/ /_/g'
done < "myfile.txt"
This doesn't work:
awk: fatal: cannot open file `--to-bp' for reading (No such file or directory)
awk: fatal: cannot open file `--from-bp' for reading (No such file or directory)
awk: fatal: cannot open file `--r2' for reading (No such file or directory)
awk: fatal: cannot open file `--ld-window-kb' for reading (No such file or directory)
But if I run it manually, e.g.
plink --bfile mydata \
--chr 3 \
--from-bp 62297313 \
--to-bp 63097313 \
--r2 \
--ld-snp rs523534 \
--ld-window-kb 100000000 \
--ld-window 100000000 \
--ld-window-r2 0 \
--out 3_rs523534_62297313_63097313
It works fine.
Is there a way that I can better feed the variable information into the command so that it works?
If you want to run a command inline to another command, you need to use a command substitution. So instead of --chr echo $line | awk '{print $1}' \ for example, you'd write --chr $( echo $line | awk '{print $1}' ) \.
But in this case it's not necessary, since read can already split the data for you.
#!/bin/bash
while read -r arg1 arg2 arg3 arg4 ; do
<do things with your args here>
done <"myfile.txt"
read will split each line based on the contents of IFS and populate each name you give it with the corresponding token from the split line.
Probably what you want is, in pure bash
#!/bin/bash
while read -ra args; do
out="${args[*]}"
plink --bfile mydata \
--chr "${args[0]}" \
--from-bp "${args[2]}" \
--to-bp "${args[3]}" \
--r2 \
--ld-snp "${args[1]}" \
--ld-window-kb 100000000 \
--ld-window 100000000 \
--ld-window-r2 0 \
--out "processing/5_locuszoom/${out// /_}"
done < "myfile.txt"
Use of awk and sed for this task is superfluous.

Enclose text after equals with double quotes

I am getting some data and putting that into a file with a sed command
awk '/name_of_the_person/{getline; print}' file_name | cut -d '>' -f 2 | cut -f 1 -d'<' |sed 's/^/export FIRST_NAME=/' >> /tmp/source
awk '/clan_of_the_person/{getline; print}' file_name | cut -d '>' -f 2 | cut -f 1 -d'<' |sed 's/^/export LAST_NAME=/' >> /tmp/source
and then I finally source this file to export the variables.
The problem that I am facing is that sometimes some people have multiple first names and last names and my file ends up like this
export FIRST_NAME=JEAN PAUL
export LAST_NAME=SMITH
This ends up breaking my export statement. Is there a way I can add quotes after the = till the end of the line so that it becomes
export FIRST_NAME="JEAN PAUL"
With GNU sed and a back-reference:
echo 'export FIRST_NAME=JEAN PAUL' | sed -E 's/=(.*)/="\1"/'
Output:
export FIRST_NAME="JEAN PAUL"
You could use a subshell to isolate the match. This has an added advantage of taking out the sed:
echo "export FIRST_NAME=\"$(awk '/name_of_the_person/{getline; print}' file_name | cut -d '>' -f 2 | cut -f 1 -d'<')\"" >> /tmp/source
echo "export LAST_NAME=\"$(awk '/clan_of_the_person/{getline; print}' file_name | cut -d '>' -f 2 | cut -f 1 -d'<')\"" >> /tmp/source
It might look cleaner with separate variables:
fname="$(awk '/name_of_the_person/{getline; print}' file_name | cut -d '>' -f 2 | cut -f 1 -d'<')"
lname="$(awk '/clan_of_the_person/{getline; print}' file_name | cut -d '>' -f 2 | cut -f 1 -d'<')"
{
echo "export FIRST_NAME=\"$fname\""
echo "export LAST_NAME=\"$lname\""
} >> /tmp/source

BASH Free Space Script: Variation

I made a script in order to check the available space on root, /var, /tmp, /usr and /opt since I need 1.5G free on each of them. Of course, there are times when all those are in root, not in another partitions.
But I got some error from my script:
1- Sometimes the output its weird when it runs in a non-English System.
2- --output in df -h its not available since some systems are old.
I want to change this script a little bit since I want it to work in every machine and I would like to ask for ideas.
I have tested the script on 650 machines already. 140 of them created the problems that I mention.
printf "root=" ; df -h --output=avail / | grep -v Avail | xargs | tr -d '[:space:]'
printf ",opt=" ; df -h --output=avail /opt | grep -v Avail | xargs | tr -d '[:space:]'
printf ",usr=" ; df -h --output=avail /usr | grep -v Avail | xargs | tr -d '[:space:]'
printf ",tmp=" ; df -h --output=avail /tmp | grep -v Avail | xargs | tr -d '[:space:]'
printf ",var=" ; df -h --output=avail /var | grep -v Avail | xargs
1- Problem:
Wrong: root=Dispo 1.5G,var=Dispo 1.5G,usr=Dispo 1.5G,tmp=Dispo
1.5G,opt=Dispo 1.5G
Correct: root=1.5G,var=1.5G,usr=1.5G,tmp=1.5G,opt=1.5G
2- Problem:
df: Unbekannte Option »--output=avail«
„df --help“ gibt weitere Informationen.
root= opt= usr= tmp= var=
EDIT:
Looks like #CharlesDufy answer worked. I made the script like this:
#!/bin/bash
sudo df -h / /var /tmp /opt /usr > freespace.txt
rootSpace=$(awk "NR==2 { print $4 }" freespace.txt)
varSpace=$(awk "NR==3 { print $4 }" freespace.txt)
tmpSpace=$(awk "NR==4 { print $4 }" freespace.txt)
optSpace=$(awk "NR==5 { print $4 }" freespace.txt)
usrSpace=$(awk "NR==6 { print $4 }" freespace.txt)
customProp="root=$rootSpace,var=$varSpace,tmp=$tmpSpace,opt=$optSpace,usr=$usrSpace"
#and the rest....
Also I want to ask 2 more questions:
Is it possible to take the freespace.txt output without creating a file?
If the 4 folders are in root, like they are not separte partitions, my output looks like this
root=12G,var=12G,tmp=12G,opt=12G,usr=12G
Is there a way to make an output like this without tons of IF, ELIF or ELSE comands?
root=12G,var=root,tmp=root,opt=root,usr=root

Need help escaping from awk quotations in bash script

I have an alias in my bashrc file that outputs current folder contents and system available storage, updated continuously by the watch function.
alias wtch='watch -n 0 -t "du -sch * -B 1000000 2>/dev/null | sort -h && df -h -B 1000000| head -2 | awk '{print \$4}'"'
The string worked fine until I put in the awk part. I know I need to escape the single quotation marks, while still staying in the double quotation marks and the $4 but I haven't been able to get it to work. What am I doing wrong?
This is the error I get
-bash: alias: $4}": not found
Since the quoting for the alias is making it tough, you could just make it a function instead:
wtch() {
watch -n 0 -t "du -sch * -B 1000000 2>/dev/null | sort -h && df -h -B 1000000| head -2 | awk '{print $4}'"
}
This is a lot like issue 2 in the BashFAQ/050
Also, a minor thing but you can skip the head process at the end and just have awk do it, even exiting after the second row like
wtch() {
watch -n 0 -t "du -sch * -B 1000000 2>/dev/null | sort -h && df -h -B 1000000| awk '{print $4} NR >= 3 {exit}'"
}
In this case you can use cut instead of awk. And you'll have the same effect.
alias wtch="watch -n 0 -t 'du -sch * -B 1000000 2>/dev/null | sort -h && df -h -B 1000000| head -2 | cut -d\ -f4'"
Explaining cut:
-d option defines a delimiter
-d\ means that my delimiter is space
-f selects a column
-f4 gives you the fourth column

BASH:How do i make output like in watch command

My linux 'watch' command is quite old and doesn't support '--color' option. How can I have same output like it does? because in my script the loop gives output one after another(of course). But i need it to replace the previous. Is there any tricks with terminal output?
#!/bin/bash
while true
do
/usr/sbin/asterisk -rx "show queue My_Compain" \
| grep Agent \
| grep -v \(Unavailable\) \
| sort -t"(" -k 2 \
| GREP_COLOR='01;31' egrep -i --color=always '^.*[0-9] \(Not in use.*$|$' \
| GREP_COLOR='01;36' egrep -i --color=always '^.*\(Busy*$|$'
sleep 2
done
You can use clear to clear the screen before dumping your output to give the appearance of in-place updates.
To reduce blinking, you can use the age old technique of double buffering:
#!/bin/bash
while true
do
buffer=$(
clear
/usr/sbin/asterisk -rx "show queue My_Compain" \
| grep Agent \
| grep -v \(Unavailable\) \
| sort -t"(" -k 2 \
| GREP_COLOR='01;31' egrep -i --color=always '^.*[0-9] \(Not in use.*$|$' \
| GREP_COLOR='01;36' egrep -i --color=always '^.*\(Busy*$|$'
)
echo "$buffer"
sleep 2
done

Resources