Parse files to get a specific constant and its integer to store into an array - bash

I have several Exception classes like this one (is PHP, but it doesnt matter right now):
class FileNotFoundException extends OtherException {
const DEFAULT_FILE_NOT_FOUND_ERROR_CODE = 159;
public function __construct($code=self::DEFAULT_FILE_NOT_FOUND_ERROR_CODE) {
parent::__construct($code);
}
}
The Problem
I need to get the error codes from all files to store them into an array (the index is the error code, and the value is the constant name) to just print it with order.
Tips
All the files are .php files
The constant error codes are always like const DEFAULT_[A-Z_]_ERROR_CODE = [0-9]+;
I tried to be stored in an array like this array[159]="DEFAULT_FILE_NOT_FOUND_ERROR_CODE";
What have I done
What I tried to do --with my little bashscripting knowledge-- is a script that parses all this php exception files and gets only the constant DEFAULT_[...]_ERROR_CODE = "number";
This is my script.sh trying to get it:
#! /bin/bash
sed -n "s/const \(DEFAULT[A-Z_]*\) = \([0-9]*\);/$array[\2]=\1;/p" $1
And if I do this:
script.sh < FileNotFoundException.php
It outputs [159]=DEFAULT_FILE_NOT_FOUND_ERROR_CODE;
Then I tried to put a variable "array" in there, like this:
eval('$array(`sed -n "s/const \(DEFAULT[A-Z_]*\) = \([0-9]*\);/$array[\2]=\1;/p" $1`)')
and several other combinations, but with no success.
Why I'm posting this in stackOverflow
I wanted to know if is possible to solve it and how, or if there is other way easier to do it.
Thanks

Remove the "$" in front of array:
#! /bin/bash
sed -n "s/.*const \(DEFAULT[A-Z_]*\) = \([0-9]*\);.*/array[\2]=\1;/p" $1
Now it will output array[159]=DEFAULT_FILE_NOT_FOUND_ERROR_CODE; which can be eval'd to set array elements:
eval "$(find yourdir -name '*.php' -exec cat {} + | yourscript)"
(I also added some .*s to the sed expression so that appending a $(rm -ri /) to the line in the php script won't cause you to evaluate it.)

Related

Shell Script msg() echo "${RED}$#${NOCOLOR}", What does it mean [duplicate]

Sometimes I have a one-liner that I am repeating many times for a particular task, but will likely never use again in the exact same form. It includes a file name that I am pasting in from a directory listing. Somewhere in between and creating a bash script I thought maybe I could just create a one-liner function at the command line like:
numresults(){ ls "$1"/RealignerTargetCreator | wc -l }
I've tried a few things like using eval, using numresults=function..., but haven't stumbled on the right syntax, and haven't found anything on the web so far. (Everything coming up is just tutorials on bash functions).
Quoting my answer for a similar question on Ask Ubuntu:
Functions in bash are essentially named compound commands (or code
blocks). From man bash:
Compound Commands
A compound command is one of the following:
...
{ list; }
list is simply executed in the current shell environment. list
must be terminated with a newline or semicolon. This is known
as a group command.
...
Shell Function Definitions
A shell function is an object that is called like a simple command and
executes a compound command with a new set of positional parameters.
... [C]ommand is usually a list of commands between { and }, but
may be any command listed under Compound Commands above.
There's no reason given, it's just the syntax.
Try with a semicolon after wc -l:
numresults(){ ls "$1"/RealignerTargetCreator | wc -l; }
Don't use ls | wc -l as it may give you wrong results if file names have newlines in it. You can use this function instead:
numresults() { find "$1" -mindepth 1 -printf '.' | wc -c; }
You can also count files without find. Using arrays,
numresults () { local files=( "$1"/* ); echo "${#files[#]}"; }
or using positional parameters
numresults () { set -- "$1"/*; echo "$#"; }
To match hidden files as well,
numresults () { local files=( "$1"/* "$1"/.* ); echo $(("${#files[#]}" - 2)); }
numresults () { set -- "$1"/* "$1"/.*; echo $(("$#" - 2)); }
(Subtracting 2 from the result compensates for . and ...)
You can get a
bash: syntax error near unexpected token `('
error if you already have an alias with the same name as the function you're trying to define.
The easiest way maybe is echoing what you want to get back.
function myfunc()
{
local myresult='some value'
echo "$myresult"
}
result=$(myfunc) # or result=`myfunc`
echo $result
Anyway here you can find a good how-to for more advanced purposes

How do I recursively replace part of a string with another given string in bash?

I need to write bash script that converts a string of only integers "intString" to :id. intString always exists after /, may never contain any other types (create_step2 is not a valid intString), and may end at either a second / or end of line. intString may be any 1-8 characters. Script needs to be repeated for every line in a given file.
For example:
/sample/123456/url should be converted to /sample/:id/url
and /sample_url/9 should be converted to /sampleurl/:id however /sample_url_2/ should remain the same.
Any help would be appreciated!
It seems like the long way around the problem to go recursive but then I don't know what problem you are solving. It seems like a good sed command like
sed -E 's/\/[0-9]{1,}/\/:id/g'
could do it in one shot, but if you insist on being recursive then it might go something like this ...
#!/bin/bash
function restring()
{
s="$1"
s="$(echo $s | sed -E 's/\/[0-9]{1,}/\/:id/')"
if ( echo $s | grep -E '\/[0-9]{1,}' > /dev/null ) ; then
restring $s
else
echo $s
exit
fi
echo $s
}
restring "$1"
now run it
$ ./restring.sh "/foo/123/bar/456/baz/45435/andstuff"
/foo/:id/bar/:id/baz/:id/andstuff

Bash scripting: variable is not incrementing correctly

I am writing a bash script to loop through all the directories and rename the directory to the value of the array, but it seems my (i th) value is not incrementing correctly and it also says "(i th) command not found" when I run my bash script.
Here is my code: I replaced the values inside Unix with place holder values.
#!/bin/bash
declare -a Unix=(value1 value2 value3 .... );
i = 0
for d in */; do
echo ${Unix[$i]}
#mv $d ${Unix[$i]}
(($i+1))
done
You are doing two things wrong. Firstly , to answer your problem,
(($i+1))
should be
(($i+=1))
also, you should remove the spaces in the line
i = 0
so it looks like
i=0
Firstly, you might want to quote your directory names in the mv command, or you get into trouble with names containing spaces:
mv "$d" "${Unix[i]}"
As you see, it's not necessary to prepend the i in the index with $, as [] is an "arithmetic context" here and expands variable names.
Secondly, your increment does nothing: you just add 1 to i and throw the result away. You can use the increment operator instead:
(( ++i ))
Again, the $ is not needed.

Integrate bash function return values

I have a function:
something() {
if [ something ]; then
echo "Something.";
return 0;
else
echo "Not something.";
return 1;
fi
}
I call it in a loop, it actually validates some files and counts how many files were valid:
find . -type l | while read line ; do something "$line"; done
I need to count how many files were invalid, therefore how many times the function has returned 0. I was thinking about this:
INVALID=0;
find . -type l | while read line ; do INVALID=$(($INVALID + something "$line")); done
Needless to say, bash doesn't buy it. Note a few things:
The info within something must be print in stdout.
The info print does not always correlate with file validity in my code. It's just info for the user.
The return value isn't directly available for arithmetic like that. You can either call the function then access $?, or branch based on the result of the function, like so:
INVALID=0
while IFS= read -r line; do
something "$line" || ((++INVALID))
done < <(find . -type l)
Also note that you can't change variables inside a pipeline. Pipelines run in subshells and have their own copies of variables. You'll need to restructure the loop to run without a pipeline to have the changes to $INVALID stick: change find | loop to loop < <(find).
It's also a good idea to use read -r to disable backslash escapes and clear out $IFS to handle lines with leading whitespace better.

Bash: iterate through files based on regex parameter

There are several posts about iterating through bash files like this:
count_files() {
count=0
for f in "filename_*.txt"
do
count=$(($count + 1))
done
echo "Current count:$count"
}
I need to pass in "filename_*.txt" as a param when calling the bash script. Like this:
$: count_files.sh "filename_*.txt"
$: count_files.sh "different_filename_*.txt"
This, however, only gets the first file:
count_files() {
count=0
for f in $1
do
count=$(($count + 1))
done
echo "Current count:$count"
}
How do I pass in a regex param and iterate through it?
NOTE: counting the files is just an example. If you have a simple way to do that, please share, but that's not the main question.
Inside count_files.sh script make sure you call function with quotes like this:
count_files "$1"
instead of:
count_files $1
Later will get you count=1 because wildcard will be expanded before function call to the first file name.

Resources