How do i unstrip an object file? - gcc

How do i unstrip a stripped object file ?
Does eu-unstrip from elfutils can make this for me ?
I need this to convert a zImage kernel to vmlinux without recompiling.
This is apart of my script:
magic="1f 8b 08 00"
full_line=$(od -A d -t x1 zImage | grep "$magic" )
offset_full_line=$( echo $full_line | cut -f1 -d" ")
data_full_line=$( echo $full_line | cut -f1 -d" " --complement )
index=$[ $( awk -v a="$data_full_line" -v b="$magic" 'BEGIN{print index(a,b)}' ) / 3 ]
offset=$[ 10#$offset_full_line + $index ]
dd if=zImage bs=1 skip=$offset 2>/dev/null | zcat > vmlinux
But my result vmlinux has an unknown format because it doesn't contain ELF headers, so how can i recover those headers ?

Your question makes no sense. If the object file has been stripped, then obviously the information is no longer there. You've got nowhere to extract the stripped data from.

Related

Show two things side by side using catimg (like in neofetch)

I am trying to create something like neofetch does using bash.
I want to show one image on the right and one ascii art (using the cat << EOF myascii EOF command)
So that I can show a logo and a text on the other side.
I want to use it as my login welcome screen when I ssh some of my machines.
So I was able to show the ascii art by doing :
cat << EOF
_____ _
|_ _| | |
| | ___ ___| |_
| |/ _ \/ __| __|
| | __/\__ \ |_
\_/\___||___/\__|
EOF
And showing my image using catimg myimage.png
However I try to show them both side by side. I tried using pr.
pr -m -t <(catimg) <(cat mytestfile.txt) but it doesn't work and it cuts my ascii art.
It's the same using the paste command.
Was anyone able to do it. If yes how ?
My ascii art is quiet long too so without it to be cutted it would be awesome.
Thanks for your help.
Produce txt file by merging ouput of catimg and figlet
Instead of real merge, I will simply put both output at correct place by using ANSI escape code
{
mapfile aa < <(figlet -w40 $text)
printf "%s" "${aa[#]}"
catimg -w40 "$image" |
sed "\$!s/^/\o33[40C/;1s/^/\o33[${#aa[#]}A/"
} >outputfile.txt
This could be written as a function:
mkTextImage() {
local aa width=${COLUMNS} prcent=50 text image lwidth rwidth ffont
while [ "${1::1}" == "-" ] ;do
case $1 in
-w) shift;width=$1;shift;;
-p) shift;prcent=$1;shift;;
-f) shift;ffont="-f $1";shift;;
esac
done
text="$1" image="$2"
printf -v lwidth %.0f $(
bc -l <<<"$width/100*$prcent")
rwidth=$((width-lwidth))
mapfile aa < <(figlet -w$lwidth $ffont $text)
printf "%s" "${aa[#]}"
catimg -w$rwidth "$image" |
sed "\$!s/^/\o33[${lwidth}C/;1s/^/\o33[${#aa[#]}A/"
}
And reversed:
(Nota: This work while catimg length stay bigger than figlet length)
mkImageText () {
local aa fl width=${COLUMNS} prcent=50 text image lwidth rwidth ffont
while [ "${1::1}" == "-" ] ;do
case $1 in
-w) shift;width=$1;shift;;
-p) shift;prcent=$1;shift;;
-f) shift;ffont="-f $1";shift;;
esac
done
image="$1" text="$2"
printf -v lwidth %.0f $(bc -l <<<"$width/100*$prcent")
rwidth=$((width-lwidth))
mapfile aa < <(catimg -w$lwidth "$image")
printf "%s" "${aa[#]}"
printf "\e[$((${#aa[#]}-1))A"
mapfile fl < <(figlet -w$rwidth $ffont "$text")
printf "\e[${lwidth}C%s" "${fl[#]}"
printf "\e[$((${#aa[#]}-${#fl[#]}-1))B"
}
From there, regarding your comment: try using 42% of 80 columns width for image:
mkImageText -f small -p 42 spongebob.png "Sponge Bob"
or
mkTextImage -f small -p 58 "Sponge Bob" spongebob.png
Will render:
Then you could try using -f smblock option, or modify functions to use toilet instead of figlet...

Replace value of a specific column from a file

I have file whose size is approx 1 GB and that file has a data in below format .
A|CD|44123|0|0
B|CD|44124|0|0
C|CD|44125|0|0
D|CD|44126|0|0
E|CD|44127|0|0
F|CD|44128|0|0
J|CD|44129|0|0
I|CD|44130|0|0
In this file I have to replace the third column value from a value which i will get after conversion . For which i have to open this file and then read the file and replace it . This process is taking around 5 hours .Below is the code which i am using
cat $FILE_NAME |\
while read REC
do
DATE=`echo "$REC" | cut -d\| -f3`
DATE_NEW=`$UTIL $DATE | head -1 |cut -d" " -f12`
RECORD="$DATE_NEW,"
echo "$RECORD" >> $New_File
done
Is there a way we can make this more better and fast.
Desired output will be like this where DATE_NEW value will be placed on each 3rd column DATE_NEW value will be the converted value which I will get from this
DATE_NEW=`$UTIL $DATE | head -1 |cut -d" " -f12`
A|CD|10/20/2020|0|0
B|CD|10/25/2020|0|0
C|CD|10/25/2020|0|0
D|CD|10/25/2020|0|0
E|CD|11/15/2020|0|0
F|CD|11/14/2020|0|0
J|CD|11/16/2020|0|0
I|CD|11/17/2020|0|0
After the comment from #Sundeep Why is using a shell loop to process text considered bad practice? I wrote the logic in Perl and from 5-7 hours processing time in Perl it took 99 Seconds to get the job done.
Give this a try:
awk -v cmd="Cmd2GetNEWDATE" 'BEGIN{FS=OFS="|"}{cmd|getline v;close(cmd)}$3=v' file

Bash: concatenated variables derived from text file using grep gives confused output

In my directory, I have a multiple nifti files (e.g., WIP944_mp2rage-0.75iso_TR5.nii) from my MRI scanner accompanied by text files (e.g., WIP944_mp2rage-0.75iso_TR5_info.txt) containing information on the acquisition parameters (e.g., "Series description: WIP944_mp2rage-0.75iso_TR5_INV1_PHS_ND"). Based on these parameters (e.g., INV1_PHS_ND), I need to change the nifti file name, which are echoed in $niftibase. I used grep to do this. When echoing all variables individually, it gives me what I want, but when I try to concatenate them into one filename, the variables are mixed together, instead of delimited by a dot.
I tried multiple forms of sed to cut away potentially invisible characters and identified the source of the problems: the "INV1_PHS_ND" part of 'series description' gives me troubles, which is the $struct component, potentially due to the fact that this part varies in how many fields are extracted. Sometimes this is 3 (in the case of INV1_PHS_ND), but it can be 2 as well (INV1_ND). When I introduce this variable into the filename, everything goes haywire.
for infofile in ${PWD}/*.txt; do
# General characteristics of subjects (i.e., date of session, group number, and subject number)
reco=$(grep -A0 "Series description:" ${infofile} | cut -d ' ' -f 3 | cut -d '_' -f 1)
date=$(grep -A0 "Series date:" ${infofile} | cut -c 16-21)
group=$(grep -A0 "Subject:" ${infofile} | cut -d '^' -f 2 | cut -d '_' -f 1 )
number=$(grep -A0 "Subject:" ${infofile} | cut -d '^' -f 2 | cut -d '_' -f 2)
ScanNr=$(grep -A0 "Series number:" ${infofile} | cut -d ' ' -f 3)
# Change name if reco has structural prefix
if [[ $reco = *WIP944* ]]; then
struct=$(grep -A0 "Series description: WIP944" ${infofile} | cut -d '_' -f 4,5,6)
niftibase=$(basename $infofile _info.txt).nii
#echo ${subStudy}.struct.${date}.${group}.${protocol}.${paradigm}.nii
echo ${subStudy}.struct.${struct}.${date}.${group}.${protocol}${number}.${paradigm}.n${ScanNr}.nii
#mv ${niftibase} ${subStudy}.struct.${struct}.${date}.${group}.${protocol}${number}.${paradigm}.n${ScanNr}.nii
fi
done
This gives me output like this:
.niit47.n4lot.Noc002
.niit47.n5lot.Noc002D
.niit47.n6lot.Noc002
.niit47.n8lot.Noc002
.niit47.n9lot.Noc002
.niit47.n10ot.Noc002
.niit47.n11ot.Noc002D
for all 7 WIP944 files. However, it needs to be in the direction of this:
H1.struct.INV2_PHS_ND.190523.Pilot.Noc001.Heat47.n11.nii, where H1, Noc, and Heat47 are loaded in from a setup file.
EDIT: I tried to use awk in the following way:
reco=$(awk 'FNR==8 {print;exit}' $infofile | cut -d ' ' -f 3 | cut -d '_' -f 1)
date=$(awk 'FNR==2 {print;exit}' $infofile | cut -c 15-21)
group=$(awk 'FNR==6 {print;exit}' $infofile | cut -d '^' -f 2 | cut -d '_' -f 1 )
number=$(awk 'FNR==6 {print;exit}' $infofile | cut -d '^' -f 2 | cut -d '_' -f 2)
ScanNr=$(awk 'FNR==14 {print;exit}' $infofile | cut -d ' ' -f 3)
which again gave me the correct output when echoing the variables individually, but not when I tried to combine them: .niit47.n11022_PHS_ND.
I used echo "$struct" | tr -dc '[:print:]' | od -c to see if there were hidden characters due to line endings, which resulted in:
0000000 I N V 2 _ P H S _ N D
0000013
EDIT: This is how the text file looks like:
Series UID: 1.3.12.2.1107.5.2.34.18923.2019052316005066316714852.0.0.0
Study date: 20190523
Study time: 153529.718000
Series date: 20190523
Series time: 160111.750000
Subject: MDC-0153,pilot_003^pilot_003
Subject birth date: 19970226
Series description: WIP944_mp2rage-0.75iso_TR5_INV1_PHS_ND
Image type: ORIGINAL\PRIMARY\P\ND
Manufacturer: SIEMENS
Model name: Investigational_Device_7T
Software version: syngo MR B17
Study id: 1
Series number: 5
Repetition time (ms): 5000
Echo time[1] (ms): 2.51
Inversion time (ms): 900
Flip angle: 7
Number of averages: 1
Slice thickness (mm): 0.75
Slice spacing (mm):
Image columns: 320
Image rows: 320
Phase encoding direction: ROW
Voxel size x (mm): 0.75
Voxel size y (mm): 0.75
Number of volumes: 1
Number of slices: 240
Number of files: 240
Number of frames: 0
Slice duration (ms) : 0
Orientation: sag
PixelBandwidth: 248
I have one of these for each nifti file. subStudy is hardcoded in a setup file, which is loaded in prior to running the for loop. When I echo this, it shows the correct value. I need to change the names of multiple files with a specific prefix, which are stored in $reco.
As confirmed in comments, the input files have DOS carriage returns, which are basically invalid in Unix files. Also, you should pay attention to proper quoting.
As a general overhaul, I would recommend replacing the entire Bash script with a simple Awk script, which is both simpler and more idiomatic.
for infofile in ./*.txt; do # no need to use $(PWD)
# Pre-filter with a simple grep
grep -q '^Series description: [^ _]*WIP944' "$infofile" && continue
# Still here? Means we want to rename
suffix="$(awk -F : '
BEGIN { split("Series description:Series date:Subject:Series number", f, /:/) }
{ sub(/\r/, ""); } # get rid of pesky DOS carriage return
NR == 1 { nifbase = FILENAME; sub(/_info\.txt$/, ".nii", nifbase) }
$1 in f { x[$1] = substring($0, length($1)+2) }
END {
split(x["Series description"], t, /_/); struct=t[4] "_" t[5] "_" t[6]
split(x["Series description"], t, /_/); reco = t[1]
date=substr(x["Series date"], 16, 5)
split(x["Subject"], t, /\^/); split(t[2], tt, /_/); group=tt[1]
number=tt[2]
ScanNr=x["Series number"]
### FIXME: protocol and paradigm are still undefined
print struct "." date "." group "." protocol number "." paradigm ".n" ScanNr
}' "$infofile")"
echo mv "$infofile" "$subStudy.struct.$suffix"
done
This probably still requires some tweaking (at least "protocol" and "paradigm" are still undefined). Once it seems to print the correct values, you can remove the echo before mv and have it actually rename files for you.
(Probably still better test on a copy of your real data files first!)

Count specific character in each line of at text and remove this character in a specific position until this character has a specific count

Hello i need help with one script that its on Solaris system:
I will explain the script analytically:
i have these files :
i)
cat /tmp/BadTransactions/TRANSACTIONS_DAILY_20180730.txt
201807300000000004
201807300000000005
201807300000000006
201807300000000007
201807300000000008
201807200002056422
201807230003099849
201807230003958306
201806290003097219
201806080001062012
201806110001633519
201806110001675603
ii)
cat /tmp/BadTransactions/test_data_for_validation_script.txt
20180720|201807200002056422||57413620344272|030341-213T |580463|WIRE||EUR|EUR|20180720|20180720|||||||00000000000019.90|00000000000019.90|Debit||||||||||MPA|||574000|129|||||||||||||||||||||||||31313001103712|BFNJKL|K| I P P BONNIER PUBLICATIO|||FI|PERS7
20180723|201807230003099849||57100440165173|140197-216U|593619|WIRE||EUR|EUR|20180723|20180723|||||||00000000000060.00|00000000000060.00|Debit||||||||||MPA|||571004|106|||||||||||||||||||||||||57108320141339|Ura Basket / UraNaiset|||-div|||FI|PERS
20180723|201807230003958306||57206820079775|210489-0788|593619|WIRE||EUR|EUR|20180721|20180723|||||||00000000000046.00|00000000000046.00|Debit||||||||||MPA|||578800|106|||||||||||||||||||||||||18053000009026|IC Kodit||| c/o Newsec Asset Manag|||FI|PERS
20180629|201806290003097219||57206820079775|210489-0788|593619|WIRE||EUR|EUR|20180628|20180629|||||||00000000000856.00|00000000000856.00|Debit||||||||||MPA|||578800|106|||||||||||||||||||||||||18053000009018|IC Kodit||| c/o Newsec Asset Manag|||FI|PERS
20180608|201806080001062012||57206820079441|140197-216S|580463|WIRE||EUR|EUR|20180608|20180608|||||||00000000000019.90|00000000000019.90|Debit||||||||||MPA|||541002|129|||||||||||||||||||||||||57108320141339|N FN|K| IKI I P BONNIER PUBLICATION|||FI|PERS7
20180611|201806110001633519||57206820079525|140197-216B|593619|WIRE||EUR|EUR|20180611|20180611|||||||00000000000242.10|00000000000242.10|Debit||||||||||MPA|||535806|106|||||||||||||||||||||||||57108320141339|As Oy Haikkoonsilta|| mannerheimin|||FI|PERS9
20180611|201806110001675603||57206820079092|140197-216Z|580463|WIRE||EUR|EUR|20180611|20180611|||||||00000000000019.90|00000000000019.90|Debit||||||||||MPA|||536501|129|||||||||||||||||||||||||57108320141339|N ^NLKL|K| I P NJ BONNIER PUBLICAT|||FI|PERS7
The script has to check each line of the
/tmp/BadTransactions/TRANSACTIONS_DAILY_20180730.txt and if the strings are on
the /tmp/BadTransactions/test_data_for_validation_script.txt it will create a
new file `/tmp/BadTransactions/TRANSACTIONS_DAILY_NEW_20180730.txt
From this new file it will count all the " | " in each line and if its more than 64 it will delete the " | " in 61th posistion of the line . This will be continued until its line has 64 pipes.
For example if one line has 67 " | " it will delete the 61th , then it will check it again and now has 66 " | | so it will delete the 61th " | " , etc... until it reach 64 pipes.So all the line have to have 64th " | ".
Here is my code , but in this code i have managed to delete only the 61th pipe in each line , i cannot make the loop so that it will check each line until it reach the 64 pipes.
I will appreciate it if you could help me.
#!/bin/bash
PATH=/usr/xpg4/bin:/bin:/usr/bin
while read line
do
grep "$line" /tmp/BadTransactions/test_data_for_validation_script.txt
awk 'NR==FNR { K[$1]; next } ($2 in K)' /tmp/BadTransactions/TRANSACTIONS_DAILY_20180730.txt FS="|" /opt/NorkomC
onfigS2/inbox/TRANSACTIONS_DAILY_20180730.txt > /tmp/BadTransactions/TRANSACTIONS_DAILY_NEW_20180730.txt
sed '/\([^|]*[|]\)\{65\}/ s/|//61' /tmp/BadTransactions/TRANSACTIONS_DAILY_NEW_20180730.txt
done < /tmp/BadTransactions/TRANSACTIONS_DAILY_20180730.txt > /tmp/BadTransactions/TRANSACTIONS_DAILY_NEW_201807
30.txt
Ok, in this problem you have several pieces of code.
You need to read a file line by line
Check each line against another file
Examine the matching line for the occurrences of "|"
Delete recursively the 61st "|" until the string will remain with 64 of them
You could do something like this
#!/bin/bash
count() { ### We will use this to count how many pipes are there
string="${1}"; shift
char="${1}"
printf "%s" "${string}" | grep -o -e "${char}" | grep -c .
}
file1="/tmp/BadTransactions/TRANSACTIONS_DAILY_20180730.txt" ### File to read
file2="/tmp/BadTransactions/test_data_for_validation_script.txt" ### File to check for duplicates
file3="/tmp/BadTransactions/TRANSACTIONS_DAILY_NEW_20180730.txt" ### File where to save our final work
printf "" > "${file3}" ### Delete (eventual) history
exec 3<"${file1}" ### Put our data in file descriptor 3
while read -r line <&3; do ### read each line and put it in var "$line"
string="$(grep -e "${line}" "${file2}")" ### Check the line against second file
while [ "$(count "${string}" "|")" -gt 64 ]; do ### While we have more than 64 "|"
string="$(printf "%s" "${string}" | sed -e "s/|//61")" ### Delete the 61st occurrence
done
printf "%s" "${string}" >> "${file3}" ### Save the correct line in the third file
done
exec 3>&- ### Clean file descriptor 3
This is not tested, but should work.
N.B. Please note that I am giving for granted that grep will return only one occurrence from second file...
If it is not your case you have to manually check each value with something like:
for value in $(grep -e "${line}" "${file2}"); do
...
done
EDIT:
For systems like Solaris or others that doesn't have GNU grep installed you can substitute the count method as follow:
count() {
string="${1}"; shift
char="${1}"
printf "%s" "${string}" | awk -F"${char}" '{print NF-1}'
}

Bash script, parsing binary number from obase to string?

I am working on a script which does subnet calculations. So far, it looks like this (in part):
echo "Subnet Address : "$sn1.$sn2.$sn3.$sn4
echo "BCast Address : "$br1.$br2.$br3.$br4
echo -e "\nSubnet address in binary" :
echo "obase=2;$ip1"+"obase=2;$ip2"+"obase=2;$ip3"+"obase=2;$ip4" \
| bc | awk '{printf("%08d",$ip1)}'
echo -e "\nBroadcast address in binary" :
echo "obase=2;$br1"+"obase=2;$br2"+"obase=2;$br3"+"obase=2;$br4" \
| bc | awk '{printf("%08d",$br1)}'
which gives me this output:
Subnet address in binary :
11000010101010100000001100000000
Broadcast address in binary :
11000010101010100000001100011111
I tried '{printf("%08d.",$br1)}' and '{printf(".%08d",$br1)}' to separate the octets but I get an extra dot on the beginning or at the end.
I want to calculate how many aces the netmask has, but I really cant find a way to get the output of the echo "obase=2;$br1"+"obase=2;$br2"+"obase=2;$br3"+"obase=2;$br4"| bc | awk to a string so I can count them.
Any suggestions?
So you want the output to be in the format of: 01111111.00000000.00000000.00000001?
Well, the cheat method, I used when I banged my head against this was to wrap around ipcalc:
%ipcalc 127.0.0.1
Address: 127.0.0.1 01111111.00000000.00000000. 00000001
Netmask: 255.255.255.0 = 24 11111111.11111111.11111111. 00000000
Wildcard: 0.0.0.255 00000000.00000000.00000000. 11111111
=>
Network: 127.0.0.0/24 01111111.00000000.00000000. 00000000
HostMin: 127.0.0.1 01111111.00000000.00000000. 00000001
HostMax: 127.0.0.254 01111111.00000000.00000000. 11111110
Broadcast: 127.0.0.255 01111111.00000000.00000000. 11111111
Hosts/Net: 254 Class A, Loopback
And then extract what I needed. Runs MUCH faster than parsing multiple times through 'bc'. Ie, no sense re-inventing the wheel if you don't need to.
If you do feel like re-inventing the wheel a bit:
$ echo "obase=2;200" + "obase=2;150" + "obase=2;200" + "obase=2;150" | \
bc | awk '{printf "%08d\." ,$1}' | \
sed -e 's/[.]*$//'
11001010.10011000.11001010.10010110
That will get you the 8 digit binary output format you want.
To separate the octets I would use printf and paste instead, e.g.:
ip1=127; ip2=0; ip3=0; ip4=1
printf "%08d\n" $(bc <<<"obase=2; $ip1; $ip2; $ip3; $ip4") | paste -sd.
Or if the ip is in one variable:
ip=127.0.0.1
printf "%08d\n" $(bc <<<"obase=2; ${ip//./;}") | paste -sd.
Output:
00001010.00101010.01100110.11111100
To count the number of 1s in a netmask just add them:
netmask=255.255.255.252
printf "%08d" $(bc <<<"obase=2; ${netmask//./;}") | grep -o . | paste -sd+ | bc
Output:
30
Two quick solutions:
$ echo $br1.$br2.$br3.$br4 |
perl -F\\\. -anE 'say join ".", map { sprintf "%08b", $_ } #F'
$ perl -e 'printf( "%08b.%08b.%08b.%08b\n", '$br1,$br2,$br3,$br4')'

Resources