Can anyone see whats wrong here? If I put X|9 in lan.db (or any db in this directory) and run the following code, the IF statement does not work. It's weird! if you echo $LINE, it is indeed pulling X|9 out of lan.db (or any db in this directory) and setting it equal to LINE, but it wont do the comparison.
DBREGEX="^[0-9]|[0-9]$"
shopt -s nullglob
DBARRAY=(databases/*)
i=0
for i in "${!DBARRAY[#]}"; do
cat ${DBARRAY[$i]} | grep -v \# | while read LINE; do
echo "$LINE" (Whats weird is that LINE DOES contain X|9)
if [[ !( $LINE =~ $DBREGEX ) ]]; then echo "FAIL"; fi
done
done
If however I just manually sent LINE="X|9" the same code (minus the while) works fine. ie LINE=X|9 fails, but LINE=9|9 succeeds.
DBREGEX="^[0-9]|[0-9]$"
Comment shopt -s nullglob
Comment DBARRAY=(databases/*)
Comment i=0
Comment for i in "${!DBARRAY[#]}"; do
Comment cat ${DBARRAY[$i]} | grep -v \# | while read LINE; do
LINE="X|9"
if [[ !( $LINE =~ $DBREGEX ) ]]; then echo "FAIL"; fi
Comment done
Comment done
* UPDATE *
UGH I GIVE UP
Now not even this is working...
DBREGEX="^[0-9]|[0-9]$"
LINE="X|9"
if [[ ! $LINE =~ $DBREGEX ]]; then echo "FAIL"; fi
* UPDATE *
Ok, so it looks like I have to escape |
DBREGEX="^[0-9]\|[0-9]$"
LINE="9|9"
echo "$LINE"
if [[ ! $LINE =~ $DBREGEX ]]; then echo "FAIL"; fi
This seems to work ok again
| has a special meaning in a regular expression. ^[0-9]|[0-9]$ means "starts with a digit, or ends with a digit". If you want to match a literal vertical bar, backslash it:
DBREGEX='^[0-9]\|[0-9]$'
for LINE in 'X|9' '9|9' ; do
echo "$LINE"
if [[ ! $LINE =~ $DBREGEX ]] ; then echo "FAIL" ; fi
done
You don't need round brackets in regex evaluation. You script is also creating a sub shell and making a useless use of cat which can be avoided.
Try this script instead:
while read LINE; do
echo "$LINE"
[[ "$LINE" =~ $DBREGEX ]] && echo "PASS" || echo "FAIL"
done < <(grep -v '#' databases/lan.db)
Related
I'm trying to automate a build process by replacing .js chunks for particular lines in my main.config.php file. When I run the following code:
declare -a js_strings=("footer." "footerJQuery." "headerCSS." "headerJQuery.")
build_path="./build/build"
config_path="./system/Config/main.config.php"
while read -r line;
do
for js_string in ${js_strings[#]}
do
if [[ $line == *$js_string* ]]
then
for js_file in "$build_path"/*
do
result="${js_file//[^.]}"
if [[ $js_file == *$js_string* ]] && [[ ${#result} -eq 3 ]]
then
sed -i "s/$line/$line$(basename $js_file)\";/g" $config_path
fi
done
fi
done
done < "$config_path"
I get this message back, and file has not been updated/edited:
sed: 1: "./system/Config/main.co ...": invalid command code .
I haven't been able to find anything in my searches that pertain to this specific message. Does anyone know what I need to change/try to get the specific lines replaced in my .php file?
Updated script with same message:
declare -a js_strings=("footer." "footerJQuery." "headerCSS." "headerJQuery.")
build_path="./build/build"
config_path="./system/Config/main.config.php"
while read -r line;
do
for js_string in ${js_strings[#]}
do
if [[ $line == *$js_string* ]]
then
for js_file in "$build_path"/*
do
result="${js_file//[^.]}"
if [[ $js_file == *$js_string* ]] && [[ ${#result} -eq 3 ]]
then
filename=$(basename $js_file)
newline="${line//$js_string*/$filename\";}"
echo $line
echo $newline
sed -i "s\\$line\\$newline\\g" $config_path
echo ""
fi
done
fi
done
done < "$config_path"
Example $line:
$config['public_build_header_css_url'] = "http://localhost:8080/build/headerCSS.js";
Example $newline:
$config['public_build_header_css_url'] = "http://localhost:8080/build/headerCSS.7529a73071877d127676.js";
Updated script with changes suggested by #Vercingatorix:
declare -a js_strings=("footer." "footerJQuery." "headerCSS." "headerJQuery.")
build_path="./build/build"
config_path="./system/Config/main.config.php"
while read -r line;
do
for js_string in ${js_strings[#]}
do
if [[ $line == *$js_string* ]]
then
for js_file in "$build_path"/*
do
result="${js_file//[^.]}"
if [[ $js_file == *$js_string* ]] && [[ ${#result} -eq 3 ]]
then
filename=$(basename $js_file)
newline="${line//$js_string*/$filename\";}"
echo $line
echo $newline
linenum=$(grep -n "^${line}\$" ${config_path} | cut -d':' -f 1 )
echo $linenum
[[ -n "${linenum}" ]] && sed -i "${linenum}a\\
${newline}
;${linenum}d" ${config_path}
echo ""
fi
done
fi
done
done < "$config_path"
Using sed's s command to replace a line of that complexity is a losing proposition, because whatever delimiter you choose may appear in the line and mess things up. If these are in fact entire lines, it is better to delete them and insert a new one:
linenum=$(fgrep -nx -f "${line}" "${config_path}" | awk -F : "{print \$1}" )
[[ -n "${linenum}" ]] && sed -i "" "${linenum}a\\
${newline}
;${linenum}d" "${config_path}"
What this does is search for the line number of the line that matches $line in its entirety, then extracts the line number portion. fgrep is necessary otherwise the symbols in your file are interpreted as regular expressions. If there was a match, then it runs sed, appending the new line (a) and deleting the old one (d).
I'm looking for help with my shell... Hope I'll find it here...
Here's my code :
#!/bin/sh
while IFS= read -r line || [ -n "$line" ]
do
[[ "$line" =~ ^[[:space:]]*\# ]] && continue # This line must stay
[[ "$line" =~ *read[[:space:]]-r[[:space:]]line* ]] && continue
echo "${line%$NL}"
done < $0
First test will suppress "only comment lines".
Second test purpose is to suppress the "while IFS= read..." lines - no matter what, it's just a test :-)
"done < $0" has been here written intentionaly... for the test !
Running the shell outputs this :
while IFS= read -r line || [ -n "$line" ]
do
[[ "$line" =~ ^[[:space:]]*\# ]] && continue # This line must stay
[[ "$line" =~ *read[[:space:]]-r[[:space:]]line* ]] && continue
echo "${line%$NL}"
done < $0
as I thought the first line will be gone because of matching then 2nd test.
What's my mistake ?
For the record, I don't want to use extra sed or awk sentence.
Actually, the input data (here $0 file) has to be standard input (eg extract from tee command). I read lot of stackOverflow subject about this, with sed or awk responses that didn't match my purpose.
The regex is invalid. A short test shows:
> [[ 'while IFS= read -r line || [ -n "$line" ]' =~ *read[[:space:]]-r[[:space:]]line* ]]
> echo $?
2
The * can't be "alone" - it can't be the first character in a POSIX extended regular expression. It has to "bind" to something, ex. a dot .. A dot represents any character. You want:
[[ $line =~ .*read[[:space:]]-r[[:space:]]line.* ]]
Problem is presence of starting quantifier * in the regex in second continue line. You may use:
[[ "$line" =~ read[[:space:]]+-r[[:space:]]+line ]] && continue
There is no need to match anything before read or after line in this regex.
Also it is better to use quantifier + after [[:space:]] to make it match 1 or more white spaces.
You can do more refactoring and combine both regex into one by using alternation as in this code:
while IFS= read -r line || [[ -n $line ]]
do
[[ $line =~ ^[[:space:]]*#|read[[:space:]]+-r[[:space:]]+line ]] && continue
echo "${line%$NL}"
done < $0
When I try to match a string and do some conditions; it always fails to do so.
date=`date +%Y%m%d`
kol="/home/user/test_$date"
regex='Terminating the script'
if [ -f $kol ]; then
sudo tail -f $kol | while read line; do
if [[ $line = *"Terminating the"* ]]
then
echo "failed"
else
echo $line >> /home/user/test123_$date
fi
else
echo "File is not yet present"
exit 0
fi
I have also tried with regex and that to failed. So when ever I input the matching string into the file ($path) it wont output "failed"; Is there anything wrong in the code. Help is much appreciated.
You can try this. At least it works for me:
sudo tail -f $1 | while read line; do
if [[ $line = '' ]]
then
break
fi
if [[ $line = *"Terminating the"* ]]
then
echo "failed"
else
echo $line >> /home/nurzhan/test123_$date
fi
done < "$1"
$path is parameter to the running script. Also note that by default the command tail returns only 10 last lines.
I am very new to Bash Scripting and I have a question regarding my CheckOurCodingRules.sh script:
I want to search for every 'hPar,' in a textfile and if found it should be checked if there is a also a 'const' in the same row.
Thats what I got so far but there is something wrong here:
while read line
do
if [[ $line == *hPar\,* ]] && [[ $line == *const\*]];then
DOCUMENTATION_TEST_A=1
else
echo DOCUMENTATION_TEST_A=0
fi
done < $INPUT_FILE
if [[DOCUMENTATION_TEST_A=0]];then
echo "error: Rule1: No const before hpar"
fi
There are a couple of issues with your script, see the code below which works for me:
DOCUMENTATION_TEST_A=0 # initial value
while read line
do
# spaces between conditional and brackets, no backslashes
if [[ $line == *hPar,* ]] && [[ $line == *const* ]]
then
DOCUMENTATION_TEST_A=1
break # optional, no need to scan the rest of the file
fi
done < $INPUT_FILE
# spaces and $, -eq is used for numerical comparisons
if [[ $DOCUMENTATION_TEST_A -eq 0 ]];
then
echo "error: Rule1: No const before hpar"
fi
A cleaner solution would be to use grep:
if ! grep "hPar," $INPUT_FILE | grep "const" >/dev/null
then
echo "error: Rule1: No const before hpar"
fi
abc.txt as
* This
Data1
Dat2
* Comment
data2
data3
When $line gets * as first char it does not work. It echoes garbage.
I tried various way but couldn't make it to work, how to check '*' in ksh varaible
while read line
do
fchar=`echo "$line" | cut -c 1-1`
#echo $fchar
if [[ ${char} = "*" ]]; then
continue
fi
if [[ ${char} = "#" ]]; then
continue
fi
echo ${line} >> stuff.txt
done<$abc.txt
Thanks.
Needs more quotes.
echo "$line" >>stuff.txt
...not
echo $line >>stuff.txt
...as the latter string-splits and glob-expands contents of the line, so it replaces * with a list of files in the current directory, replaces foo[bar] with foob if a file by that name exists, etc.
By the way, you'd be better off opening stuff.txt only once, not re-opening it every single time you want to add a new line. That'd look like this:
while read; do
fchar=${REPLY:0:1}
[[ "$fchar" = "*" ]] && continue
[[ "$fchar" = "#" ]] && continue
printf '%s\n' "$REPLY"
done >stuff.txt <abc.txt
By the way, you could also do this trivially with grep:
grep -E -v '^[*#]' <abc.txt >stuff.txt