Shell script to make directories and subdirectories with variable names - bash

I'm trying to create script to be run by cron to create multiple folders with subfolders.
DATE=`date +%Y-%m-%d`
IP_ADDR=`ifconfig | grep -v '127.0.0.1' | sed -n 's/.*inet addr:\([0-9.]\+\)\s.*/\1/p'`
/bin/mkdir -p /mnt/db-backup/12/$DATE/$IP_ADDR/
If i run this script manually everything is created as expected. When script is ran by cron subdirectory $IP_ADDR is not created and there is no errors.

I suspect that /sbin is not part of the PATH for the environment that the cron job runs under. You should specify the full path for the ifconfig command:
IP_ADDR=$(/sbin/ifconfig | grep -v '127.0.0.1' | sed -n 's/.*inet addr:\([0-9.]\+\)\s.*/\1/p')
It's also better practice (in general) to use $() for command substitution.

Try to use debug mode :
set -x
DATE=`date +%Y-%m-%d`
IP_ADDR=`ifconfig | grep -v '127.0.0.1' | sed -n 's/.*inet addr:\([0-9.]\+\)\s.*/\1/p'`
/bin/mkdir -p /mnt/db-backup/12/$DATE/$IP_ADDR/
set +x
Then, redirect the output of your cron to a file and have a look, you should find useful information in it.

You are not far off, but there are several ordering caveats that could cause problems. Many systems have different formats for the ifconfig output line. Some with inet xxx.xxx.xxx.xxx, others with inet addr:xxx.xxx.xxx.xxx. (those are the two most common). You may also need to handle the case where there are multiple wired inet interfaces (2+ NICs in the box). However, if you have only 1 NIC, you could try the following to handle the common ifconfig formats:
DATE=`date +%Y-%m-%d`
IP_ADDR=$(ifconfig |
grep -v '127.0.0.1' |
grep -E 'inet[ ](addr:)*[0-9]{1,3}([.][0-9]{1,3}){3}' |
sed -e 's/^.*inet \(addr:\)*//' -e 's/ .*$//')
/bin/mkdir -p /mnt/db-backup/12/$DATE/$IP_ADDR/
or with IP_ADDR written as one line:
IP_ADDR=$(ifconfig | grep -v '127.0.0.1' | grep -E 'inet[ ](addr:)*[0-9]{1,3}([.][0-9]{1,3}){3}' | sed -e 's/^.*inet \(addr:\)*//' -e 's/ .*$//')

Related

Cron job creates empty files

I want to preface that I am a newbie that picked up shell scripting 2 weeks ago.
Hey guys I need help with something, hope someone can point me in the right direction. I have a script that works when I run it from the command line but every time I run it with a crontab, the output is a few empty files. Does anyone know why?
That's the code down there
#!/bin/bash
#Provide an IP address as an argument to use nmap
#make sure to add the full range with (0-225 or 0/24) at the end
IPADDRESS=$(hostname -I | awk '{print $1}')
network-scan(){
if [ $1 ]
then
sudo nmap -sn $1
else
sudo nmap -sn 192.168.1.0-255
fi
}
#Scan the whole network and only prints the IP addresses minus your own
#Sends the IP addresses to a file
network-scan | grep -i 'Nmap scan report' | \
sed 's/\ /\n/g'|sed 's/(//g'|sed 's/)//g' | \
grep '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*' | grep -v ${IPADDRESS} > ip_addresses
#Scan the whole network and only prints the MAC addresses
#Sends the MAC addresses to a file
network-scan | grep -i 'MAC Address:' | \
awk '{print $3}' > mac_addresses
#Put the IP and MAC addresses in the same file
paste ip_addresses mac_addresses | \
column -s $'\t' -t > "scan_$(date +%d-%m-%Y_%H:%M:%S)"
#Notify that a file with the IP and MAC addresses has been created on the Desktop
echo "A file containing the results of the scan has been created on the Desktop"
exit 0
You are using
network-scan | grep
without passing any parameter.
Hence network-scan function always using
sudo nmap -sn 192.168.1.0-255
when you run it from command line are you passing any parameter ?
echo $IPADDRESS inside the script when executing at cron and at command line for debugging.
network-scan | grep -i 'Nmap scan report' | \
sed 's/\ /\n/g'|sed 's/(//g'|sed 's/)//g' | \
grep '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*' | grep -v ${IPADDRESS}
Since you are obtaining empty output, validate each command and append(test) each OR operators to know where it is removing required output.

How to run a command like xargs on a grep output of a pipe of a previous xargs from a command in Bash

I'm trying to understand what's happening here out of curiosity, even though I can just copy and paste the output of the terminal to do what I need to do. The following command does not print anything.
ls /opt/local/var/macports/registry/portfiles -1 | sed 's/-.*//g' | sort -u | parallel "sudo port -N install" {} 2>&1 | grep -Po "Use '\K.*(?=')" | parallel "{}"
The directory I call ls on contains a bunch of filenames starting with the string I want to extract that ends at the first dash (so stringexample-4.2009 pipes stringexample into parallel (like xargs but to run each line separately). After running the command sudo port install <stringexample>, I get error outputs like so:
Unable to activate port <stringexample>. Use 'port -f activate <stringexample>' to force the activation.
Now, I wish to run port -f activate <stringexample>. However, I cannot seem to do anything with the output port -f activate gettext that I get to the terminal.
I cannot even do ... | grep -Po "Use '\K.*(?=')" | xargs echo or ... | grep -Po "Use '\K.*(?=')" >> commands_to_run.txt (the output stream to file only creates an empty file), despite the shorter part of the command:
ls /opt/local/var/macports/registry/portfiles -1 | sed 's/-.*//g' | sort -u | parallel "sudo port -N install {}" 2>&1 | grep -Po "Use '\K.*(?=')"
printing the commands to the terminal. Why does the pipe operator not work here? If the commands I wish to run are outputting to the terminal, surely there's got to be a way to capture them.

How to execute a text extracted through grep and sed in bash

I am trying to execute a command based on extracting it from README file.
I was able to extract it using grep and sed:
cat README.md | grep -i "docker build" | grep -vi "dockerfile.debug" | sed 's/.*\(d[a-z]\).*/\1/'
This script would give a result something like 'docker build .'
I want to execute that command.
But I am not sure how to execute the extracted text. I thought 'exec' would work but I couldn't apply it. Please help me find a way to execute the text extracted through the above script.
Set your command in
$(CommandToExecute)
or back-ticks
`CommandToExecute`
As Example:
$(cat README.md | grep -i "docker build" | grep -vi "dockerfile.debug" | sed 's/.*\(d[a-z]\).*/\1/'
);
try:
$(grep -i "docker build" README.md | grep -vi "dockerfile.debug" | sed 's/.*\(d[a-z]\).*/\1/')

How to escape shell script to run it using command_string option?

I am trying to escape the following script to run it via shell command-string option ( /bin/sh -c ).
privateIP=$(ifconfig eth0 | grep "inet " | awk \'{print $2}\');
sed -i "s/http:\/\/:/http:\/\/$privateIP:/g" init.conf
Please elaborate on the answer.
You're question is not clear, but perhaps you are looking for:
sh -c 'privateIP=$(ifconfig eth0 | awk "/inet/{print \$2}");
sed -i "s#http://:#http://$privateIP:#g" init.conf'

tcpdump: Output only source and destination addresses

Problem description:
I want to print only the source and destination address from a tcpdump[1].
Have one working solution, but believe it could be improved a lot. An example that captures 5 packets, just as an example of what I'm looking for:
tcpdump -i eth1 -n -c 5 ip | \
cut -d" " -f3,5 | \
sed -e 's/^\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\)\..* \([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*$/\1 > \2/'
Question:
Can this be done in any easier way? Performance is also an issue here.
[1] A part of a test if the snort home_net is correctly defined, or if we see traffic not defined in the home_net.
Solution:
Ok, thanks to everyone who have replied to this one. There have been two concerns related to the answers, one is the compatibility across different linux-versions and the second one is speed.
Here is the results on the speed test I did. First the grep-version:
time tcpdump -l -r test.dmp -n ip 2>/dev/null | grep -P -o '([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*? > ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' | grep -P -o '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | xargs -n 2 echo >/dev/null
real 0m5.625s
user 0m0.513s
sys 0m4.305s
Then the sed-version:
time tcpdump -n -r test.dmp ip | sed -une 's/^.* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..*$/\1 > \3/p' >/dev/null
reading from file test.dmp, link-type EN10MB (Ethernet)
real 0m0.491s
user 0m0.496s
sys 0m0.020s
And the fastest one, the awk-version:
time tcpdump -l -r test.dmp -n ip | awk '{ print gensub(/(.*)\..*/,"\\1","g",$3), $4, gensub(/(.*)\..*/,"\\1","g",$5) }' >/dev/null
reading from file test.dmp, link-type EN10MB (Ethernet)
real 0m0.093s
user 0m0.111s
sys 0m0.013s
Unfortunately I have not been able to test how compatible they are, but the awk needs gnu awk to work due to the gensub function. Anyway, all three solutions works on the two platforms I have tested them on. :)
Here's one way using GNU awk:
tcpdump -i eth1 -n -c 5 ip | awk '{ print gensub(/(.*)\..*/,"\\1","g",$3), $4, gensub(/(.*)\..*/,"\\1","g",$5) }'
Try this:
tcpdump -i eth1 -n -c 5 ip 2>/dev/null | sed -r 's/.* ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).* > ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*/\1 > \2/'
If running from a .sh script, remember to escape \1 & \2 as required.
Warning You have to use unbuffered ou line-buffered output to monitor the output of another command like tcpdump.
But you command seem correct.
To simplify, you could:
tcpdump -i eth1 -n -c 5 ip |
sed -une 's/^.* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..*$/\1 > \3/p'
Notice the u switch usefull without -c 5 at tcpdump
tcpdump -ni eth1 ip |
sed -une 's/^.* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..* \(\([0-9]\{1,3\}\.\?\)\{4\}\)\..*$/\1 > \3/p'
& here is a grep only solution:
tcpdump -l -i eth1 -n -c 5 ip 2>/dev/null | grep -P -o '([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+).*? > ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)' | grep -P -o '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | xargs -n 2 echo
Note -l, in case you don't want to limit the number of packets using -c.

Resources