Parse /proc/mounts and substitude only one field - bash

I am looking for a way to print informations from /proc/mounts like that:
/home /dev/md9 /dev/mapper/home home
/var/tmp /dev/md7 /dev/mapper/vartmp vartmp
I try:
awk '{ print $2 " " $1; gsub("/","",$2); print "/dev/mapper/"$2" "$2 }' /proc/mounts
But the result is on two lines:
/home /dev/mapper/home
/dev/mapper/home home
/var/tmp /dev/md7
/dev/mapper/vartmp vartmp
Does anyone have a solution?

fix
use printf ( to avoid the implicit linefeed )
add whitespace to separate the printf from the gsub output
adjusted command
awk '{ printf $2 " " $1 " "; gsub("/","",$2); print "/dev/mapper/"$2" "$2 }' /proc/mounts
input.txt
/dev/mapper/home /home blah blah blah blah
output
$ awk '{ printf $2 " " $1 " "; gsub("/","",$2); print "/dev/mapper/"$2" "$2 }' input.txt
/home /dev/mapper/home /dev/mapper/home home

Related

Bash loop to make directory, if numerical id found in file

I'm trying to use awk to create sub-directories in a directory (which is always the last line of file1, each block separated by an empty line), if the number in line 2 (always the first 6 digits in the format xx-xxxx) of file2 is found in $2 of file1.
The directory will already be created in /path/to/directory. In the example below, Directory2_2 already exists in /path/to/directory and since 19-0003, 19-0004 and 19-0005 are found in $2 of file1, they are moved to Directory2_2.
file1
xxxx_006 19-0000_Lname-yyyy-zzzzz
xxxx_007 19-0001_Lname-yyyy-zzzzz
Directory1_1
xxxx_008 19-0003_Lname-yyyy-zzzzz
xxxx_009 19-0004_Lname-yyyy-zzzzz
xxxx_020 19-0005_Lname-yyyy-zzzzz
Directory2_2
file2
xxxx
19-0003-xxx-xxx-xxx_000-111
yyyy
xxxx
19-0004-xxx-xxx-xxx_000-111
yyyy
xxxx
19-0005-xxx-xxx-xxx_000-111
yyyy
awk in bash for loop
for f in $(awk { print cut -d'_' -f1 }' file2); do
[[ "$f" == $2 ]] && mkdir -p "$f" /path/to/directory
done
desired output
Directory2_2
19-0003-xxx-xxx-xxx_000-111
19-0004-xxx-xxx-xxx_000-111
19-0005-xxx-xxx-xxx_000-111
If the directory names don't contain spaces (below file1 processed in paragraph-mode and file2 in line-mode.):
awk 'NR==FNR { for(i=2; i<NF; i+=2) a[substr($i,1,7)] = $NF; next }
{ k = substr($0, 1, 7) }
k in a { cmd = sprintf("mkdir -p %s/%s", a[k], $0); print(cmd); }
' RS= file1 RS='\n' file2
#mkdir -p Directory2_2/19-0003-xxx-xxx-xxx_000-111
#mkdir -p Directory2_2/19-0004-xxx-xxx-xxx_000-111
#mkdir -p Directory2_2/19-0005-xxx-xxx-xxx_000-111
change print(cmd) to system(cmd) to actually run the command.
Note: if the directory names contain spaces, you might need to setup IFS='\n' in order to use $NF for the base directory in file1:
awk 'NR==FNR { for(i=1; i<NF; i++) a[substr($i,index($i," ")+1,7)] = $NF; next }
{ k = substr($0, 1, 7) }
k in a { cmd = sprintf("mkdir -p \"%s\"/\"%s\"", a[k], $0); print(cmd); }
' FS='\n' RS= file1 RS='\n' file2
Could you please try following.
awk -v path_val="/your_path/" '
FNR==NR{
if($0 ~ /^[0-9]+/){
a[substr($0,1,7)]=$0
}
next
}
/^Directory/{
if(count==value){
print "Directory " $0 " all elements are present." ORS "Going to write shell script code now..."
print $0 ORS val
print "*************************************************"
print "if [[ -d " path_val $0 " ]]" ORS "then" ORS\
" cd " path_val $0 ORS " mkdir " val ORS\
" if [[ $? -eq 0 ]]" ORS " then" ORS \
" echo " s1 "Directories named "\
val s1 " created successfully in path " path_val\
"." s1 ORS " else" ORS " echo " s1\
"kindly check from your end once seems directories not created." s1\
ORS " fi" ORS "else" ORS " echo " s1\
"Please check seems base directory " path_val " NOT present itself."\
s1 ORS "fi"
}
count=val=value=""
}
($3 in a){
val=(val?val OFS a[$3]:a[$3])
count++
}
/^xxx/{
value++
}' Input_file2 FS="[ _]" Input_file1
Explanation what code does is:
1- Code has variable named /your_path/ which is your BASE path where directories will be created etc.
2- It will check if all the lines coming before Directory_...(para by para) keyword from Input_file1 is present in Input_file2 if yes, then it will print output of those lines along with directory name + it will write code on console too(bash code which checks about your base directory path and then creates the matched directories inside base directory). As of now I am simply printing it you could either take it to .ksh file(as an output file) and could run it OR you could add | bash at the end of this code. I haven't tested it I leave this up to OP.
Following will be the output:
Directory Directory2_2 all elements are present.
Going to write shell script code now...
Directory2_2
19-0003-xxx-xxx-xxx_000-111 19-0004-xxx-xxx-xxx_000-111 19-0005-xxx-xxx-xxx_000-111
*************************************************
if [[ -d /your_path/Directory2_2 ]]
then
cd /your_path/Directory2_2
mkdir 19-0003-xxx-xxx-xxx_000-111 19-0004-xxx-xxx-xxx_000-111 19-0005-xxx-xxx-xxx_000-111
if [[ $? -eq 0 ]]
then
echo Directories named 19-0003-xxx-xxx-xxx_000-111 19-0004-xxx-xxx-xxx_000-111 19-0005-xxx-xxx-xxx_000-111 created successfully in path /your_path/.
else
echo kindly check from your end once seems directories not created.
fi
else
echo Please check seems base directory /your_path/ NOT present itself.
fi
PS: As mentioned above take final shell code which should create directories in system either in output_file or run it by using | bash etc at end of awk code I haven't tested it. Please DO NOT run code without testing. Statements are very simply you can go through them and should test it in a test directory/test environment only.

Arguments to change variable values in Bash script

i have this script in bash:
#!/bin/bash
dir="/home/dortiz/Prueba"
for i in $dir/*
do
cat $i | awk '{print $1" " $2" " $3" " $4"\n " $5}' | \
awk '/gi/{print ">" $0; getline; print}' | \
awk '$3>20.00 {print $0; getline; print;}' \
> "${i}.outsel"
done
cd /home/dortiz/Prueba
mv *.outsel /home/dortiz/Prueba2
and i would like to set an argument to change the value after ""awk '$3>"" in an easy way from my main program that will call this script.
i have read something about getopts but i dont uderstand it at all
Thanks a lot in advance
The simplest way is to just pass an argument to your script:
yourscript.sh 20.0
Then in your script
#!/bin/bash
value=$1 # store the value passed in as the first parameter.
dir="/home/dortiz/Prueba"
for i in $dir/*; do
awk '{print $1" " $2" " $3" " $4"\n " $5}' "$i" |
awk '/gi/{print ">" $0; getline; print}' |
awk -v val="$value" '$3>val {print $0; getline; print;}' > "${i}.outsel"
# ^^^^^^^^^^^^^^^
done
...
and the cat|awk|awk|awk pipeline can probably be written like this:
awk -v val="$value" '
$3 > val {
prefix = /gi/ ? ">" : ""
print prefix $1 " " $2" " $3" " $4"\n " $5
}
' "$i" > "$i.outsel"

How to print the remaining columns using awk?

Right now I have a command that prints my log file with a delimited | per column.
cat ambari-alerts.log | awk -F '[ ]' '{print $1 "|" $2 "|" $3 "|" $4 "|" $5 "|"}' |
grep "$(date +"%Y-%m-%d")"
Sample of the log file data is this:
2016-02-11 09:40:33,875 [OK] [MAPREDUCE2] [mapreduce_history_server_rpc_latency] (History Server RPC Latency) Average Queue Time:[0.0], Average Processing Time:[0.0]
The result of my command is this:
2016-02-11|09:40:33,875|[OK]|[MAPREDUCE2]|[mapreduce_history_server_rpc_latency]
I want to print the remaining columns. How can I do that? I tried this syntax adding $0, but unfortunately it just prints the whole line again.
awk -F '[ ]' '{print $1 "|" $2 "|" $3 "|" $4 "|" $5 "|" $0}'
Hope you can help me, newbie here in using awk.
This seems to be all you need:
$ awk '{for (i=1;i<=5;i++) sub(/ /,"|")} 1' file
2016-02-11|09:40:33,875|[OK]|[MAPREDUCE2]|[mapreduce_history_server_rpc_latency]|(History Server RPC Latency) Average Queue Time:[0.0], Average Processing Time:[0.0]
This is a bit of a hassle with awk
awk -F '[ ]' '{
printf "%s|%s|%s|%s|%s|", $1, $2, $3, $4, $5
for (i=6; i<=NF; i++) printf "%s ", $i
print ""
}'
or, replace the first 5 spaces:
awk -F '[ ]' '{
sub(/ /, "|");sub(/ /, "|");sub(/ /, "|");sub(/ /, "|");sub(/ /, "|")
print
}'
This is actually easier in bash
while IFS=" " read -r a b c d e rest; do
echo "$a|$b|$c|$d|$e|$rest"
done < file.log
Folding in your grep:
awk -F '[ ]' -v date="$(date +%Y-%m-%d)" '{
$0 ~ date {
printf "%s|%s|%s|%s|%s|", $1, $2, $3, $4, $5
for (i=6; i<=NF; i++) printf "%s ", $i
print ""
}
}'
Here is some awk that provides a somewhat more generalized approach than brute-forcing the first 5 columns:
awk '{
for (i = 1; i < 6; i++)
printf "%s|", $i
for (i = 6; i < NF; i++)
printf " %s ", $i
}' ambari-alerts.log | grep "$(date +"%Y-%m-%d")"

using if in awk in comparision with todays date

I am looking for a command which helps me use if in awk and equates it to the current date.
A/B folder has files with different dates. I need to filter out files of the present day whenever script runs
A) Gives an output with all the dates,
date=`date +"%Y-%m-%d"`
s3cmd ls --recursive s3://A/B/ | grep A-B | grep .tar | awk '{ if ($1 -eq "$date" ) print $1" "$2 " " $3 " " $4 }' | sort -r
B)Replaces $1 which contains dates with "$date" to all of them
date=`date +"%Y-%m-%d"`
s3cmd ls --recursive s3://A/B/ | grep A-B | grep .tar | awk '{ if ($1 = "$date" ) print $1" "$2 " " $3 " " $4 }' | sort -r
C)Does not give any output. leaves blank
date=`date +"%Y-%m-%d"`
s3cmd ls --recursive s3://A/B/ | grep A-B | grep .tar | awk '{ if ($1 == "$date" ) print $1" "$2 " " $3 " " $4 }' | sort -r
if I remove "" it does not give me any output in all the cases.
The shell doesn't substitute variables inside double quotes. You should assign an awk variable from the shell variable. Also, the equality comparison is ==, not -eq or =.
awk -v date="$date" '$1 == date { print $1" "$2 " " $3 " " $4 }'
You don't really need awk for that. Just use find and say
find /path/to/search/ -type f ! -newermt $(date +"%Y-%m-%d")
$(..) is command substitution and what it will do is expand to current date in the format YYYY-MM-DD.
! -newermt is find option to look for files older than specified date
-type f will only look for files
awk is not shell. It is a completely separate tool with it's own syntax and capabilities. Therefore you should not expect to be able to use shell variables or shell syntax in an awk script. Try this:
s3cmd ls --recursive s3://A/B/ |
awk -v date="$date" -v OFS=" " '/A-B/ && /.tar/ && ($1 == date) { print $1, $2, $3, $4 }' |
sort -r
You probably actually meant \.tar instead of .tar though and as #jaypal said, this is a job for find, not ls piped to awk.

Of Bash loops and if statements

I need to look at a line, and perform a quick if/then->echo on it depending on the content of column 3.
The file looks like this:
name network subnetmask
net_A 192.168.0.0 24
net_b 10.10.0.0 16
Some columns also have a blank 3rd column, and I need to have an if/then for those as well.
Psuedo-code should look like this in my mind:
snet_mask=`cat $filename | grep -i net | awk '{print $3}`
if [ $snet_mask = 24 ]
then
awk '{print "something"$1,"something else"}'
fi
if [ $snet_mask = 23 ]
then
awk '{print "something"$1,"something else"}'
fi
etc
That just doesn't work it seems, since $snet_mask becomes the value of "all" of $3, so I think I need a for loop based on grep -i net, however I don't really know.
What's the right answer? :)
Try this one-liner :
awk '$1 ~ "^net" && $3==24{print "something", $3, "something else"} $1 ~ "^net" $3==23{print "something", $3, "something else"}' file.txt
Or on multi-lines (easier to read) :
awk '
$1 ~ "^net" && $3==24{print "something", $3, "something else"}
$1 ~ "^net" && $3==23{print "something", $3, "something else"}
' file.txt
We can do it simply like this too (depends of your needs) :
awk '
$1 ~ "^net" && ($3==24 || $3==23) {print "something", $3, "something else"}
' file.txt
Or even simpler & shortest with a regex :
awk '
$1 ~ "net" && $3 ~ "^2[34]$" {print "something", $3, "something else"}
' file.txt
you could accomplish what you need in an awk statement, since you're already using awk
cat $filename | grep -i net | awk '{if($3==24) print $1; else print $0;}'
In the if statement (if 3rd col is 23), I'm printing just the first column, otherwise I'm printing everything. Obviously you can expand this to work with all of your cases
Staying in bash without external tools, you could do something like this:
while read name network netmask ; do
if [[ "$name" == net* ]] ; then
case "$netmask" in
"") echo "It's empty" ;;
24) echo "It's 24" ;;
23) echo "It's 23" ;;
*) echo "None of the above" ;;
esac
fi
done < "$filename"

Resources