So I can add a link to a debug symbol file like this objcopy --add-gnu-debuglink=$name.dbg $name, but how can I later retrieve that value again?
I checked with readelf -a and grepped for \.dbg without any luck. Similarly I checked the with objdump -sj .gnu_debuglink (.gnu_debuglink is the section) and could see the value there:
$ objdump -sj .gnu_debuglink helloworld|grep \.dbg
0000 68656c6c 6f776f72 6c642e64 62670000 helloworld.dbg..
However, would there be a command that allows me to extract the retrieve the exact value again (i.e. helloworld.dbg in the above example)? That is the file name only ...
I realize I could use some shell foo here, but it seems odd that an option exists to set this value but none to retrieve it. So I probably just missed it.
You can use readelf directly:
$ readelf --string-dump=.gnu_debuglink helloworld
String dump of section '.gnu_debuglink':
[ 0] helloworld
[ 1b] 9
I do not know what the second entry means (it seems to always be different). To get rid of the header and the offsets, you can use sed:
$ readelf --string-dump=.gnu_debuglink helloworld | sed -n '/]/{s/.* //;p;q}'
helloworld
Something like this should work:
objcopy --output-target=binary --set-section-flags .gnu_debuglink=alloc \
--only-section=.gnu_debuglink helloworld helloworld.dbg
--output-target=binary avoids adding ELF headers. --set-section-flags .gnu_debuglink=alloc is needed because objcopy only writes allocated sections by default (with the binary emulation). And --only-section=.gnu_debuglink finally identifies the answer. See this earlier answer.
Note that the generated file may have a trailing NUL byte and four bytes of CRC, so some post-processing is needed to extract everything up to the first NUL byte (perhaps using head -z -n 1 helloworld.dbg | tr -d '\0' or something similar).
Related
Content of testfile.txt
/path1/abc.txt
/path2/abc.txt.1
/path3/abc.txt123
Content of pattern.txt
abc.txt$
Bash Command
grep -i -f pattern.txt testfile.txt
Output:
/path1/abc.txt
This is a working solution, but currently the $ in the pattern is manually added to each line and this edited pattern file is uploaded to users. I am trying to avoid the manual amendment.
Alternate solution to loop and read line by line, but required scripting skills or upload scripts to user environment.
Want to keep the original pattern files in an audited environment, users just login and run simple cut-n-paste commands.
Any one liner solution?
You can use sed to add $ to pattern.txt and then use grep, but you might run into issues due to regexp metacharacters like the . character. For example, abc.txt$ will also match abc1txt. And unless you take care of matching only the basename from the file path, abc.txt$ will also match /some/path/foobazabc.txt.
I'd suggest to use awk instead:
$ awk '!f{a[$0]; next} $NF in a' pattern.txt f=1 FS='/' testfile.txt
/path1/abc.txt
pattern.txt f=1 FS='/' testfile.txt here a flag f is set between the two files and field separator is also changed to / for the second file
!f{a[$0]; next} if flag f is not set (i.e. for the first file), build an array a with line contents as the key
$NF in a for the second file, if the last field matches a key in array a, print the line
Just noticed that you are also using -i option, so use this for case insensitive matching:
awk '!f{a[tolower($0)]; next} tolower($NF) in a'
Since pattern.txt contains only a single pattern, and you don't want to change it, since it is an audited file, you could do
grep -i -f "$(<pattern.txt)'$' testfile.txt
instead. Note that this would break, if the maintainer of the file one day decided to actually write there a terminating $.
IMO, it would make more sense to explain to the maintainer of pattern.txt that he is supposed to place there a simple regular expression, which is going to match your testfile. In this case s/he can decide whether the pattern really should match only the right edge or some inner part of the lines.
If pattern.txt contains more than one line, and you want to add the $ to each line, you can likewise do a
grep -i -f <(sed 's/$/$/' <pattern.txt) testfile.txt
As the '$' symbol indicates pattern end. The following script should work.
#!/bin/bash
file_pattern='pattern.txt' # path to pattern file
file_test='testfile.txt' # path to test file
while IFS=$ read -r line
do
echo "$line"
grep -wn "$line" $file_test
done < "$file_pattern"
You can remove the IFS descriptor if the pattern file comes with leading/trailing spaces.
Also the grep option -w matches only whole word and -n provides with line number.
I'm trying to grep multiple strings which look like this (there's a few hundred) against a file which contains data:string
Example strings: (no sensitive data is provided, they have been modified).
$H$9a...DcuCqC/rMVmfiFNm2rqhK5vFW1
$H$9n...AHZAV.sTefg8ap8qI8U4A5fY91
$H$9o...Bi6Z3E04x6ev1ZCz0hItSh2JJ/
$H$9w...CFva1ddp8IRBkgwww3COVLf/K1
I've been researching how to grep a file of patterns against another file, and came across the following commands
grep -f strings.txt datastring.txt > output.txt
grep -Ff strings.txt datastring.txt > output.txt
But unfortunately, these commands do NOT work successfully, and only print out a handful of results to my output file. I think it may be something to do with the symbols contained in strings.txt, but I'm unsure. Any help/advice would be great.
To further mention, I'm using Cygwin on Windows (if this is relevant).
Here's an updated example:
strings.txt contains the following:
$H$9a...DcuCqC/rMVmfiFNm2rqhK5vFW1
$H$9n...AHZAV.sTefg8ap8qI8U4A5fY91
$H$9o...Bi6Z3E04x6ev1ZCz0hItSh2JJ/
$H$9w...CFva1ddp8IRBkgwww3COVLf/K1
datastring.txt contains the following:
$H$9a...DcuCqC/rMVmfiFNm2rqhK5vFW1:53491
$H$9n...AHZAV.sTefg8ap8qI8U4A5fY91:03221
$H$9o...Bi6Z3E04x6ev1ZCz0hItSh2JJ/:20521
$H$9w...CFva1ddp8IRBkgwww3COVLf/K1:30142
So technically, all lines should be included in the OUTPUT file, but only this line is outputted:
$H$9w...CFva1ddp8IRBkgwww3COVLf/K1:30142
I just don't understand.
You have showed the output of cat -A strings.txt elsewhere, which includes ^M representing a CR (carriage return) character at the end of each line:
This indicates your file has Windows line endings (CR LF) instead of the Unix line endings (only LF) that grep would expect.
You can convert files with dos2unix strings.txt and back with unix2dos strings.txt.
Alternatively, if you don't have dos2unix installed in your Cygwin environment, you can also do that with sed.
sed -i 's/\r$//' strings.txt # dos2unix
sed -i 's/$/\r/' strings.txt # unix2dos
I am trying to search inside a folder containing several files. The name of the files is written in upper case with a .sub extension in lower case:
AAA.sub
BBB.sub
CCC.sub
DDD.sub
I am searching a pattern trough those file using grep, however i would like to only use lower case letter for the input files.
In the man page for grep it is written:
-i, --ignore-case
Ignore case distinctions in both the PATTERN and the input files. (-i is specified by POSIX.)
So, if i understood properly:
grep -i subckt /schematics/aaa
and
grep -i subckt /schematics/AAA
Are supposed to both be able to search a pattern "subckt" in the file "aaa" regardless of its case (AAA or aaa) and if two files named aaa and AAA are present at the same time in the foler, i expect grep to search trough both of them.
However when i try my search with the 1st instruction (lower case) it does not work, giving me "no such file or directory" message.
When i try to search with the 2nd instruction (upper case) it works properly.
I obviously understood something wrong about how the -i option with grep, can anyone give me an answer regarding this matter?
Is it possible to be case insensitive with the input files when using grep?
EDIT:
My question was lacking details, even tough i have found the answer to my problem i will add the details in case someone else stumbles upon this:
I have one file that contains a list of each file name i want to grep. My list looks like this:
aaa capacitor C_0
bbb capacitor C_0
ccc resistor R_in
...
The grep is done inside a perl script, the perl script parses the list file and gets the name of each individual file name (aaa bbb ccc) inside a while loop.
However the name inside the list file is written in lower case whereas the name of the files i want to grep is written in upper case.
This is why i wanted to have the input file search to be case insensitive so that i could directly do a grep -i subck aaa and it would search inside the file 'AAA'
However, since the grep is launched from a perl script, and since it is apparently not possible to have grep behave like that, i used the uc() function of perl to convert aaa to AAA and do my grep with it. (see my answer below)
-i affects how the contents are searched, not the name of the files.
When the man page says "Ignore case distinctions in both the PATTERN and the input files." that really means that case is ignored in the pattern ( searching for AAA and aaa are equivalent) and the contents of the input files (a line would match if it includes "AAA" or "aaa" or even "AaA")
I think you want to either list all the filenames on the command line, or find a glob (i.e. wildcard) that matches all the filenames:
grep -i subckt *.sub
In Unix/Linux shells (bash, zsh, and so on) "*" is processed by the shell (bash) not the command (grep). The command receives the list of files and actually can't tell the difference between whether a user typed "grep foo *" and "grep foo file1 file2 file3" (if the directory includes those 3 files)
Please try the following command
find . -iname aaa.sub | grep -rn subckt
find with -iname option will list out files ignoring their case. In the above case find . -iname will list out both aaa.sub & AAA.sub. The output is piped to the grep command.
I have found a way to circumvent my problem by using the uc (upper case) function of perl to convert the input files for the grep function into upper case.
The grep command was launched from a perl script in the first place:
grep -i subckt /schematics/aaa
So, i just did that in my perl script:
$tmp=aaa
$tmp=uc($tmp)
grep -i subckt /schematics/$tmp
Now, the "aaa" name is just an example. In the perl script it is recovered from another parsed file that is written in lower case.
Thanks for the answers tough.
grep uses the filenames as they are listed on the command line. The -i option affects the contents of the files, not the names of the files.
You can use find to select filenames to be searched. The -iname option lets you match files ignoring case.
grep subckt $(find /schematics -iname aaa.sub -print)
If you have many filenames, or those filenames include spaces or other characters that would confuse the shell, the safe and secure way to do this is using the -print0 and -0 options:
find /schematics -iname aaa.sub -print0 | xargs -r -0 grep -i subckt
In my build settings i have define some preprocessor macros
i.e. SANDBOX_ENV=1
I want to use the value of SANDBOX_ENV in my shell script.
I have tried echo "SANDBOX value is = ${GCC_PREPROCESSOR_DEFINITIONS}"
but its giving me all macros values like DEBUG=1 SANDBOX_ENV=1 COCOAPODS=1
I want to use value that is assigned to SANDBOX_ENV
Try this:
#!/bin/bash
GCC_PREPROCESSOR_DEFINITIONS="DEBUG=1 SANDBOX_ENV=1 COCOAPODS=1"
# delete everything before our value ans stuff into TMPVAL
TMPVAL="${GCC_PREPROCESSOR_DEFINITIONS//*SANDBOX_ENV=/}"
# remove everything after our value from TMPVAL and return it
TMPVAL="${TMPVAL// */}"
echo $TMPVAL; #outputs 1
HTH,
bovako
You should be able to parse it easily with awk or something, but here's how I'd do it:
echo $GCC_PREPROCESSOR_DEFINITIONS | grep -Po 'SANDBOX_ENV=\d+' | sed 's/SANDBOX_ENV=//'
In your echo context:
echo "SANDBOX value is $(echo $GCC_PREPROCESSOR_DEFINITIONS | grep -Po 'SANDBOX_ENV=\d+' | sed 's/SANDBOX_ENV=//')"
Basically I piped the contents of GCC_PREPROCESSOR_DEFINITIONS and grepped out the SANDBOX_ENV portion.
grep -P
is to use the Perl regex \d+, because I don't like POSIX. Just a preference. Essentially what
grep -P 'SANDBOX_ENV=\d+'
does is to find the line in the content piped to it that contains the string "SANDBOX_ENV=" and any number of digits succeeding it. If the value might contain alphanumerics you can change the \d for digits to \w for word which encompasses a-zA-Z0-9 and you get:
grep -Po 'SANDBOX_ENV=\w+'
The + just means there must be at least one character of the type specified by the character before it, including all succeeding characters that matches.
the -o (only-matching) in grep -Po is used to isolate the match so that instead of the entire line you just get "SANDBOX_ENV=1".
This output is then piped to the sed command where I do a simple find and replace where I replaced "SANDBOX_ENV=" with "", leaving only the value behind it. There are probably easier ways to do it like with awk, but you'll have to learn that yourself.
If you want to have something self contained within the Build Settings and you don't mind slight indirection, then:
Create User-Defined settings SANDBOX_ENV=1 (or whatever value you want)
In Preprocessor Macros, add SANDBOX_ENV=${SANDBOX_ENV}
In your shell, to test, do
echo ${SANDBOX_ENV}
With the User-Defined Settings, you'll still be able to modify the value for Build Configuration and Architecture. So, for example, you could make the Debug config be SANDBOX_ENV=0 and Release be SANDBOX_ENV=1.
Might be the obvious answer, but have you simply tried:
echo ${SANDBOX_ENV}
If that doesn't work, try using eval:
eval "${GCC_PREPROCESSOR_DEFINITIONS}"
echo ${SANDBOX_ENV}
I have the following file:
asdasd
asd
asd
incompatible:svcnotallowed:svc\:/network/bmb/clerver\:default
incompatible:svcnotallowed:svc\:/network1/bmb/clerver\:default
incompatible:svcnotallowed:svc\:/network2/bmb/clerver\:default
asdasd
asd
asd
as
And now suppose I have the two variables v1="incompatible:svcnotallowed:" and v2="svc\:/network1/bmb/clerver\:default".
I would like to search the entire file using v1 and v2. I know this is a problem caused due to the file having a'\' in it. I just dont know how to eliminate it. I have tried storing v1 and v2 (both variable contents and grep usage) using single quotes, but in vain.
This is the series of commands I have tried :
grep "$v1$v2" file
grep '$v1$v2' file
I need this to work in KSH
please let me know the right way to use grep in this scenario.
Thanks.
grep -F "$v1$v2" file should do the trick -- with the -F option, it treats the pattern as a fixed string, so backslashes don't get interpreted as escapes or backreferences.
But fgrep "$v1$v2" file would probably be the most portable solution. As tomkaith13 notes in his comment, the -F option to grep isn't universally supported. On Solaris, the default grep doesn't support -F, but the version in /usr/xpg4/bin does.
Since you are using ksh, you can just use it to read the files
v1="incompatible:svcnotallowed:"
v2="svc\:/network1/bmb/clerver\:default"
while read -r line
do
case "$line" in
"$v1$v2" ) echo "$line";;
esac
done < file