Why my default variable is not working in bash script? - bash

Here it is my script.
alias h='history "${1:-25}"'
My desirable result is when it gets variable like h 100 it shows the results of history 100 and no given inputs like h, it shows 25 elements like history 25.
But it works only when I hit h ,showing 25 results, other than that it gave me argument error.
-bash: history: too many arguments
I have tried ${1:-25} but it returns error either.
-bash: $1: cannot assign in this way
Sorry if it is duplicated, but bash script is quite tricky to look up since it has $ and numbers.

An alias can't accept parameters. They take arguments only at the end, and they are not positional (not accessible as $1, $2, etc). It's equivalent to:
alias myAlias="command opt"
myAlias $#
# Is the same as: command opt arg1 arg2 ...
You should use a bash function, one that will receive the param and call history:
function h() {
x="${1:-25}" # Take arg $1, use 25 as fallback
echo "Calling history with: $x" # Log $x value as example
history $x # Call history with $x
}
Usage:
~ $ h
Calling history with: 25
448 xxx
...
471 yyy
472 zzz
~ $ h 1
Calling history with: 1
473 h 1
~ $

Related

divide floating point numbers from two different outputs

I am writing a bash script that has 1) number of lines in a file matching a pattern and 2) total lines in a file.
a) To get the number of lines in a file within a directory that had a specific pattern I used grep -c "pattern" f*
b) For overall line count in each file within the directory I used
wc -l f*
I am trying to divide the output from 2 by 1. I have tried a for loop
for i in $a
do
printf "%f\n" $(($b/$a)
echo i
done
but that returns an error syntax error in expression (error token is "first file in directory")
I also have tried
bc "$b/$a"
which does not work either
I am not sure if this is possible to do -- any advice appreciated. thanks!
Sample: grep -c *f generates a list like this
myfile1 500
myfile2 0
myfile3 14
myfile4 18
and wc -l *f generates a list like this:
myfile1 500
myfile2 500
myfile3 500
myfile4 238
I want my output to be the outcome of output for grep/wc divided so for example
myfile1 1
myfile2 0
myfile3 0.28
myfile4 0.07
bash only supports integer math so the following will print the (silently) truncated integer value:
$ a=3 b=5
$ printf "%f\n" $(($b/$a))
1.000000
bc is one solution and with a tweak of OP's current code:
$ bc <<< "scale=2;$b/$a"
1.66
# or
$ echo "scale=4;$b/$a" | bc
1.6666
If you happen to start with real/float numbers the printf approach will error (more specifically, the $(($b/$a)) will generate an error):
$ a=3.55 b=8.456
$ printf "%f\n" $(($b/$a))
-bash: 8.456/3.55: syntax error: invalid arithmetic operator (error token is ".456/3.55")
bc to the rescue:
$ bc <<< "scale=2;$b/$a"
2.38
# or
$ echo "scale=4;$b/$a" | bc
2.3819
NOTE: in OP's parent code there should be a test for $a=0 and if true then decide how to proceed (eg, set answer to 0; skip the calculation; print a warning message) otherwise the this code will generate a divide by zero error
bash doesn't have builtin floating-point arithmetic, but it can be simulated to some extent. For instance, in order to truncate the value of the fraction a/b to two decimal places (without rounding):
q=$((100*a/b)) # hoping multiplication won't overflow
echo ${q:0:-2}.${q: -2}
The number of decimal places can be made parametric:
n=4
q=$((10**n*a/b))
echo ${q:0:-n}.${q: -n}
This awk will do it all:
awk '/pattern/{a+=1}END{print a/NR}' f*
jot 93765431 |
mawk -v __='[13579]6$' 'BEGIN {
_^=__=_*=FS=__ }{ __+=_<NF } END { if (___=NR) {
printf(" %\47*.f / %\47-*.f ( %.*f %% )\n",
_+=++_*_*_++,__,_,___,_--,_*__/___*_) } }'
4,688,271 / 93,765,431 ( 4.99999941343 % )
filtering pattern = [13579]6$

Compgen doesn't complete words containing colons correctly

I'm encountering a problem with creating a Bash completion function, when the command is expected to contain colons. When you type a command and press tab, Bash inserts the contents of the command line into an array, only these arrays are broken up by colons. So the command:
dummy foo:apple
Will become:
('dummy' 'foo' ':' 'apple')
I'm aware that one solution is to change COMP_WORDBREAKS, but this isn't an option as it's a team environment, where I could potentially break other code by messing with COMP_WORDBREAKS.
Then this answer suggests using the _get_comp_words_by_ref and __ltrim_colon_completions variables, but it is not remotely clear to me from the answer how to use these.
So I've tried a different solution below. Basically, read the command line as a string, and figure out which word the user's cursor is currently selecting by calculating an "offset". If there is a colon in the command line with text to the left or right of it, it will add 1 each to the offset, and then subtract this from the COMP_CWORD variable.
1 #!/bin/bash
2 _comp() {
3 #set -xv
4 local a=("${COMP_WORDS[#]}")
5 local index=`expr $COMP_CWORD`
6 local c_line="$COMP_LINE"
7
8 # Work out the offset to change the cursor by
9 # This is needed to compensate for colon completions
10 # Because COMP_WORDS splits words containing colons
11 # E.g. 'foo:bar' becomes 'foo' ':' 'bar'.
12
13 # First delete anything in the command to the right of the cursor
14 # We only need from the cursor backwards to work out the offset.
15 for ((i = ${#a[#]}-1 ; i > $index ; i--));
16 do
17 regex="*([[:space:]])"${a[$i]}"*([[:space:]])"
18 c_line="${c_line%$regex}"
19 done
20
21 # Count instances of text adjacent to colons, add that to offset.
22 # E.g. for foo:bar:baz, offset is 4 (bar is counted twice.)
23 # Explanation: foo:bar:baz foo
24 # 0 12 34 5 <-- Standard Bash behaviour
25 # 0 1 <-- Desired Bash behaviour
26 # To create the desired behaviour we subtract offset from cursor index.
27 left=$( echo $c_line | grep -o "[[:alnum:]]:" | wc -l )
28 right=$( echo $c_line | grep -o ":[[:alnum:]]" | wc -l )
29 offset=`expr $left + $right`
30 index=`expr $COMP_CWORD - $offset`
31
32 # We use COMP_LINE (not COMP_WORDS) to get an array of space-separated
33 # words in the command because it will treat foo:bar as one string.
34 local comp_words=($COMP_LINE)
35
36 # If current word is a space, add an empty element to array
37 if [ "${COMP_WORDS[$COMP_CWORD]}" == "" ]; then
38 comp_words=("${comp_words[#]:0:$index}" "" "${comp_words[#]:$index}" )
39 fi
40
41
42 local cur=${comp_words[$index]}
43
44 local arr=(foo:apple foo:banana foo:mango pineapple)
45 COMPREPLY=()
46 COMPREPLY=($(compgen -W "${arr[*]}" -- $cur))
47 #set +xv
48 }
49
50 complete -F _comp dummy
Problem is, this still doesn't work correctly. If I type:
dummy pine<TAB>
Then it will correctly complete dummy pineapple. If I type:
dummy fo<TAB>
Then it will show the three available options, foo:apple foo:banana foo:mango. So far so good. But if I type:
dummy foo:<TAB>
Then the output I get is dummy foo:foo: And then further tabs don't work, because it interprets foo:foo: as a cur, which doesn't match any completion.
When I test the compgen command on its own, like so:
compgen -W 'foo:apple foo:banana foo:mango pineapple' -- foo:
Then it will return the three matching results:
foo:apple
foo:banana
foo:mango
So what I assume is happening is that the Bash completion sees that it has an empty string and three available candidates for completion, so adds the prefix foo: to the end of the command line - even though foo: is already the cursor to be completed.
What I don't understand is how to fix this. When colons aren't involved, this works fine - "pine" will always complete to pineapple. If I go and change the array to add a few more options:
local arr=(foo:apple foo:banana foo:mango pineapple pinecone pinetree)
COMPREPLY=()
COMPREPLY=($(compgen -W "${arr[*]}" -- $cur))
Then when I type dummy pine<TAB> it still happily shows me pineapple pinecone pinetree, and doesn't try to add a superfluous pine on the end.
Is there any fix for this behaviour?
One approach that's worked for me in the past is to wrap the output of compgen in single quotes, e.g.:
__foo_completions() {
COMPREPLY=($(compgen -W "$(echo -e 'pine:cone\npine:apple\npine:tree')" -- "${COMP_WORDS[1]}" \
| awk '{ print "'\''"$0"'\''" }'))
}
foo() {
echo "arg is $1"
}
complete -F __foo_completions foo
Then:
$ foo <TAB>
$ foo 'pine:<TAB>
'pine:apple' 'pine:cone' 'pine:tree'
$ foo 'pine:a<TAB>
$ foo 'pine:apple'<RET>
arg is pine:apple
$ foo pi<TAB>
$ foo 'pine:

Remove last argument in shell script (POSIX)

I am currently working on a language that aims to compile to POSIX shell languages and I want to introduce a pop feature. Just like how you can use "shift" to remove the first argument passed to a function:
f() {
shift
printf '%s' "$*"
}
f 1 2 3 #=> 2 3
I want some code that when introduced below can remove the last argument.
g() {
# pop
printf '%s' "$*"
}
g 1 2 3 #=> 1 2
I am aware of the array method as detailed in (Remove last argument from argument list of shell script (bash)), but I want something portable that will work in at least the following shells: ash, dash, ksh (Unix), bash, and zsh. I also want something reasonably speedy; something that opens external processes/subshells would be too heavy for small argument counts, thought if you have a creative solution I wouldn't mind seeing it regardless (and they can still be used as a fallback for large argument counts). Something as fast as those array methods would be ideal.
This is my current answer:
pop() {
local n=$(($1 - ${2:-1}))
if [ -n "$ZSH_VERSION" -o -n "$BASH_VERSION" ]; then
POP_EXPR='set -- "${#:1:'$n'}"'
elif [ $n -ge 500 ]; then
POP_EXPR="set -- $(seq -s " " 1 $n | sed 's/[0-9]\+/"${\0}"/g')"
else
local index=0
local arguments=""
while [ $index -lt $n ]; do
index=$((index+1))
arguments="$arguments \"\${$index}\""
done
POP_EXPR="set -- $arguments"
fi
}
Note that local is not POSIX, but since all major sh shells support it (and specifically the ones I asked for in my question) and not having it can cause serious bugs, I decided to include it in this leading function. But here's a fully compliant POSIX version with obfuscated arguments to reduce the chance of bugs:
pop() {
__pop_n=$(($1 - ${2:-1}))
if [ -n "$ZSH_VERSION" -o -n "$BASH_VERSION" ]; then
POP_EXPR='set -- "${#:1:'$__pop_n'}"'
elif [ $__pop_n -ge 500 ]; then
POP_EXPR="set -- $(seq -s " " 1 $__pop_n | sed 's/[0-9]\+/"${\0}"/g')"
else
__pop_index=0
__pop_arguments=""
while [ $__pop_index -lt $__pop_n ]; do
__pop_index=$((__pop_index+1))
__pop_arguments="$__pop_arguments \"\${$__pop_index}\""
done
POP_EXPR="set -- $__pop_arguments"
fi
}
Usage
pop1() {
pop $#
eval "$POP_EXPR"
echo "$#"
}
pop2() {
pop $# 2
eval "$POP_EXPR"
echo "$#"
}
pop1 a b c #=> a b
pop1 $(seq 1 1000) #=> 1 .. 999
pop2 $(seq 1 1000) #=> 1 .. 998
pop_next
Once you've created the POP_EXPR variable with pop, you can use the following
function to change it to omit further arguments:
pop_next() {
if [ -n "$BASH_VERSION" -o -n "$ZSH_VERSION" ]; then
local np="${POP_EXPR##*:}"
np="${np%\}*}"
POP_EXPR="${POP_EXPR%:*}:$((np == 0 ? 0 : np - 1))}\""
return
fi
POP_EXPR="${POP_EXPR% \"*}"
}
pop_next is a much simpler operation than pop in posix shells (though it's
slightly more complex than pop on zsh and bash)
It's used like this:
main() {
pop $#
pop_next
eval "$POP_EXPR"
}
main 1 2 3 #=> 1
POP_EXPR and variable scope
Note that if you're not going to be using eval "$POP_EXPR" immediately after
pop and pop_next, if you're not careful with scoping some function call
inbetween the operations could change the POP_EXPR variable and mess things
up. To avoid this, simply put local POP_EXPR at the start of every function
that uses pop, if it's available.
f() {
local POP_EXPR
pop $#
g 1 2
eval "$POP_EXPR"
printf '%s' "f=$*"
}
g() {
local POP_EXPR
pop $#
eval "$POP_EXPR"
printf '%s, ' "g=$*"
}
f a b c #=> g=1, f=a b
popgen.sh
This particular function is good enough for my purposes, but I did create a
script to generate further optimized functions.
https://gist.github.com/fcard/e26c5a1f7c8b0674c17c7554fb0cd35c#file-popgen-sh
One of the ways to improve performance without using external tools here is
to realize that having several small string concatenations is slow, so doing
them in batches makes the function considerably faster. calling the script
popgen.sh -gN1,N2,N3 creates a pop function that handles the operations
in batches of N1, N2, or N3 depending on the argument count. The script also
contains other tricks, exemplified and explained below:
$ sh popgen \
> -g 10,100 \ # concatenate strings in batches\
> -w \ # overwrite current file\
> -x9 \ # hardcode the result of the first 9 argument counts\
> -t1000 \ # starting at argument count 1000, use external tools\
> -p posix \ # prefix to add to the function name (with a underscore)\
> -s '' \ # suffix to add to the function name (with a underscore)\
> -c \ # use the command popsh instead of seq/sed as the external tool\
> -# \ # on zsh and bash, use the subarray method (checks on runtime)\
> -+ \ # use bash/zsh extensions (removes runtime check from -#)\
> -nl \ # don't use 'local'\
> -f \ # use 'function' syntax\
> -o pop.sh # output file
An equivalent to the above function can be generated with popgen.sh -t500 -g1 -#.
In the gist containing popgen.sh you will find a popsh.c file that can be
compiled and used as a specialized, faster alternative to the default shell
external tools, it will be used by any function generated with
popgen.sh -c ... if it's accessible as popsh by the shell.
Alternatively, you can create any function or tool named popsh and use
it in its place.
Benchmark
Benchmark functions:
The script I used for benchmarking can be found on this gist:
https://gist.github.com/fcard/f4aec7e567da2a8e97962d5d3f025ad4#file-popbench-sh
The benchmark functions are found in these lines:
https://gist.github.com/fcard/f4aec7e567da2a8e97962d5d3f025ad4#file-popbench-sh-L233-L301
The script can be used as such:
$ sh popbench.sh \
> -s dash \ # shell used by the benchmark, can be dash/bash/ash/zsh/ksh.\
> -f posix \ # function to be tested\
> -i 10000 \ # number of times that the function will be called per test\
> -a '\0' \ # replacement pattern to model arguments by index (uses sed)\
> -o /dev/stdout \ # where to print the results to (concatenates, defaults to stdout)\
> -n 5,10,1000 # argument sizes to test
It will output a time -p style sheet with a real, user and sys time values,
as well as an int value, for internal, that is calculated inside the benchmark
process using date.
Times
The following are the int results of calls to
$ sh popbench.sh -s $shell -f $function -i 10000 -n 1,5,10,100,1000,10000
posix refers to the second and third clauses, subarray refers to the first,
while final refers to the whole.
value count 1 5 10 100 1000 10000
---------------------------------------------------------------------------------------
dash/final 0m0.109s 0m0.183s 0m0.275s 0m2.270s 0m16.122s 1m10.239s
ash/final 0m0.104s 0m0.175s 0m0.273s 0m2.337s 0m15.428s 1m11.673s
ksh/final 0m0.409s 0m0.557s 0m0.737s 0m3.558s 0m19.200s 1m40.264s
bash/final 0m0.343s 0m0.414s 0m0.470s 0m1.719s 0m17.508s 3m12.496s
---------------------------------------------------------------------------------------
bash/subarray 0m0.135s 0m0.179s 0m0.224s 0m1.357s 0m18.911s 3m18.007s
dash/posix 0m0.171s 0m0.290s 0m0.447s 0m3.610s 0m17.376s 1m8.852s
ash/posix 0m0.109s 0m0.192s 0m0.285s 0m2.457s 0m14.942s 1m10.062s
ksh/posix 0m0.416s 0m0.581s 0m0.768s 0m4.677s 0m18.790s 1m40.407s
bash/posix 0m0.409s 0m0.739s 0m1.145s 0m10.048s 0m58.449s 40m33.024s
On zsh
For large argument counts setting set -- ... with eval is very slow on zsh no
matter no matter the method, save for eval 'set -- "${#:1:$# - 1}"'. Even as
simple a modification as changing it to eval "set -- ${#:1:$# - 1}"
(ignoring that it doesn't work for arguments with spaces) makes it two orders
of magnitude slower.
value count 1 5 10 100 1000 10000
---------------------------------------------------------------------------------------
zsh/subarray 0m0.203s 0m0.227s 0m0.233s 0m0.461s 0m3.643s 0m38.396s
zsh/final 0m0.399s 0m0.416s 0m0.441s 0m0.722s 0m4.205s 0m37.217s
zsh/posix 0m0.718s 0m0.913s 0m1.182s 0m6.200s 0m46.516s 42m27.224s
zsh/eval-zsh 0m0.419s 0m0.353s 0m0.375s 0m0.853s 0m5.771s 32m59.576s
More benchmarks
For more benchmarks, including only using external tools, the c popsh tool or the naive algorithm, see this file:
https://gist.github.com/fcard/f4aec7e567da2a8e97962d5d3f025ad4#file-benchmarks-md
It's generated like this:
$ git clone https://gist.github.com/f4aec7e567da2a8e97962d5d3f025ad4.git popbench
$ cd popbench
$ sh popgen_run.sh
$ sh popbench_run.sh --fast # or without --fast if you have a day to spare
$ sh poptable.sh -g >benchmarks.md
Conclusion
This has been the result of a week-long research on the subject, and I thought
I'd share it. Hopefully it's not too long, I tried to trim it to the main
information with links to the gist. This was initially made as an answer to
(Remove last argument from argument list of shell script (bash)) but I felt the focus on POSIX
made it off topic.
All the code in the gists linked here is licensed under the MIT license.
alias pop='set -- $(eval printf '\''%s\\n'\'' $(seq $(expr $# - 1) | sed '\''s/^/\$/;H;$!d;x;s/\n/ /g'\'') )'
EDIT:
this is a POSIX shell solution that use aliases instead of functions; if called in a function, this gives the desired effect (it resets the function arguments by using the same number of arguments minus the last; being an alias, and with eval, it can change the values of the enclosing function):
func () {
pop
pop
echo "$#"
}
func a b c d e # prints a b c
pop () {
i=0
while [ $((i+=1)) -lt $# ]; do
set -- "$#" "$1"
shift
done # 1 2 3 -> 3 1 2
printf '%s' "$1" # last argument
shift # $# is now without last argument
}

What does underscore variable followed by range mean in bash: $_{0..10}

According to tldp.org, bash underscore variable is:
The underscore variable is set at shell startup and contains the absolute file name of the shell or script being executed as passed in the argument list. Subsequently, it expands to the last argument to the previous command, after expansion. It is also set to the full pathname of each command executed and placed in the environment exported to that command. When checking mail, this parameter holds the name of the mail file.
But this answer to How can I repeat a character in Bash? makes an strange use of it:
# exactly the same as perl -E 'say "=" x 100'.
echo -e ''$_{1..100}'\b='
Playing around with this variable I can't make anything out of it's semantics, so the question is what does
An string.
Followed by $_.
Followed by range expansion.
Followed by another string
mean in bash?
Sample:
$ echo $_{0..10} ; echo $_{0..10} | wc
1 0 1
$ echo ''$_{0..10}'' ; echo ''$_{0..10}'' | wc
1 0 11
$ echo ''$_{0..10}'x' ; echo ''$_{0..10}'x' | wc
x x x x x x x x x x x
1 11 22
$ echo 'x'$_{0..10}'' ; echo 'x'$_{0..10}'' | wc
x x x x x x x x x x x
1 11 22
$ echo 'ab'$_{0..10}'cd' ; echo 'ab'$_{0..10}'cd' | wc
abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd
1 11 55
echo $_{0..10}
The braces are expanded to:
echo $_0 $_1 $_2 $_3 $_4 $_5 $_6 $_7 $_8 $_9 $_10
It prints the values of eleven strangely-named variables named _0, _1, _2, and so on. They're not set—which is why you don't see anything—but if they were, you would:
$ _0=zero _1=one _2=two _3=three _4=four _5=five _6=six _7=seven _8=eight _9=nine _10=ten
$ echo $_{0..10}
zero one two three four five six seven eight nine ten
$ echo ''$_{0..10}'x'
Same thing, but now there's an x after each variable name. It's not part of the variable name. It's a separate, literal character x, as if you'd written:
echo ${_0}x ${_1}x ${_2}x ${_3}x ${_4}x ${_5}x ${_6}x ${_7}x ${_8}x ${_9}x ${_10}x
Now the output when the variables have values is:
$ _0=zero _1=one _2=two _3=three _4=four _5=five _6=six _7=seven _8=eight _9=nine _10=ten
$ echo ''$_{0..10}'x'
zerox onex twox threex fourx fivex sixx sevenx eightx ninex tenx
This should be enough to understand the other examples in your question.
It also shows that the linked answer is a poor way to repeat a string. It relies on these variables being unset. Not recommended.
That is brace expansion.
Read
info bash -n "Brace Expansion"
This expands the last command, stored in $_, with the given numbers.

Greping multiple lines from one multiline output Bash

I have a command dumpsys power with this output:
POWER MANAGER (dumpsys power)
Power Manager State: mDirty=0x0
mWakefulness=Awake #
mWakefulnessChanging=false
mIsPowered=false
mPlugType=0
mBatteryLevel=67 #
mBatteryLevelWhenDreamStarted=0
mDockState=0
mStayOn=false #
mProximityPositive=false
mBootCompleted=true #
mSystemReady=true #
mHalAutoSuspendModeEnabled=false
mHalInteractiveModeEnabled=true
mWakeLockSummary=0x0
mUserActivitySummary=0x1
mRequestWaitForNegativeProximity=false
mSandmanScheduled=false
mSandmanSummoned=false
mLowPowerModeEnabled=false #
mBatteryLevelLow=false #
mLastWakeTime=134887327 (59454 ms ago) #
mLastSleepTime=134881809 (64972 ms ago) #
mLastUserActivityTime=134946670 (111 ms ago)
mLastUserActivityTimeNoChangeLights=134794061 (152720 ms ago)
mLastInteractivePowerHintTime=134946670 (111 ms ago)
mLastScreenBrightnessBoostTime=0 (134946781 ms ago)
mScreenBrightnessBoostInProgress=false
mDisplayReady=true #
mHoldingWakeLockSuspendBlocker=false
mHoldingDisplaySuspendBlocker=true
Settings and Configuration:
mDecoupleHalAutoSuspendModeFromDisplayConfig=false
mDecoupleHalInteractiveModeFromDisplayConfig=true
mWakeUpWhenPluggedOrUnpluggedConfig=true
mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig=false
mTheaterModeEnabled=false
mSuspendWhenScreenOffDueToProximityConfig=false
mDreamsSupportedConfig=true
mDreamsEnabledByDefaultConfig=true
mDreamsActivatedOnSleepByDefaultConfig=false
mDreamsActivatedOnDockByDefaultConfig=true
mDreamsEnabledOnBatteryConfig=false
mDreamsBatteryLevelMinimumWhenPoweredConfig=-1
mDreamsBatteryLevelMinimumWhenNotPoweredConfig=15
mDreamsBatteryLevelDrainCutoffConfig=5
mDreamsEnabledSetting=false
mDreamsActivateOnSleepSetting=false
mDreamsActivateOnDockSetting=true
mDozeAfterScreenOffConfig=true
mLowPowerModeSetting=false
mAutoLowPowerModeConfigured=false
mAutoLowPowerModeSnoozing=false
mMinimumScreenOffTimeoutConfig=10000
mMaximumScreenDimDurationConfig=7000
mMaximumScreenDimRatioConfig=0.20000005
mScreenOffTimeoutSetting=60000 #
mSleepTimeoutSetting=-1
mMaximumScreenOffTimeoutFromDeviceAdmin=2147483647 (enforced=false)
mStayOnWhilePluggedInSetting=0
mScreenBrightnessSetting=102
mScreenAutoBrightnessAdjustmentSetting=-1.0
mScreenBrightnessModeSetting=1
mScreenBrightnessOverrideFromWindowManager=-1
mUserActivityTimeoutOverrideFromWindowManager=-1
mTemporaryScreenBrightnessSettingOverride=-1
mTemporaryScreenAutoBrightnessAdjustmentSettingOverride=NaN
mDozeScreenStateOverrideFromDreamManager=0
mDozeScreenBrightnessOverrideFromDreamManager=-1
mScreenBrightnessSettingMinimum=10
mScreenBrightnessSettingMaximum=255
mScreenBrightnessSettingDefault=102
Sleep timeout: -1 ms
Screen off timeout: 60000 ms
Screen dim duration: 7000 ms
Wake Locks: size=0 Suspend Blockers: size=4
PowerManagerService.WakeLocks: ref count=0
PowerManagerService.Display: ref count=1
PowerManagerService.Broadcasts: ref count=0
PowerManagerService.WirelessChargerDetector: ref count=0
Display Power: state=ON #
I want to get the lines marked with # in a format of:
mScreenOffTimeoutSetting=60000
mDisplayReady=true
***
ScreenOfftimeoutSetting = 60000
DisplayReady = true
The commands output can vary from device to device and some of the lines might not be there or are in a different place. Thus if the searched line isn't there no errors should be generated.
It's not clear what you want. Aou can use sed to extract variables form the file and do whatever you want with them. Here's an example:
sed -n -e 's/^mSomeName=\(.*\)/newVariable=\1/p' -e 's/^mOtherName=.*+\(.*\)/newVariable2=\1/p' myFile
Explanation:
-n don't output anything per default
-e an expression follows. It's required since we have multiple expressions in place
s/^mSomeName=\(.*\)/newVariable=\1/p if file starts (^) with mSomeName= capture what follows (\(.*\)), replace the line with newVariable=\1, where \1 is what got captured, and print it out (p)
's/^mOtherName=.+(.)/newVariable2=\1/p' similar to the previous expression but will capture whatere comes after a + sign and print it behind newVariable2
This does something like:
$ sed -n -e 's/^mSomeName=\(.*\)/newVariable=\1/p' -e 's/^mOtherName=.*+\(.*\)/newVariable2=\1/p' <<<$'mSomeName=SomeValue\nmOtherName=OtherValue+Somethingelse'
newVariable=SomeValue
newVariable2=Somethingelse
<<<$'...' is a way of passing a string with linebreaks \n directly to the command in bash. You can replace it with a file. This command just outputs a string, nothing will get changed.
If you need them in bash variables use eval:
$ eval $(sed -n -e 's/^mSomeName=\(.*\)/newVariable=\1/p' -e 's/^mOtherName=.*+\(.*\)/newVariable2=\1/p' <<<$'mSomeName=SomeValue\nmOtherName=OtherValue+Somethingelse')
$ echo newVariable=$newVariable - newVariable2=$newVariable2
newVariable=SomeValue - newVariable2=Somethingelse
eval will execute the string which in this case set the variable values:
$ eval a=1
$ echo $a
1
If you want to just use Grep command, you can use -A (After) and -B (Before) options and pipes.
This is a exemple with 2 lines.
File test.txt :
test
aieauieaui
test
caieaieaipe
mSomeName=SomeValue
mOtherName=OtherValue+Somethingelse
nothing
blabla
mSomeName=SomeValue2
mOtherName=OtherValue+Somethingelse2
The command to use :
grep -A 1 'mSomeName' test.txt |grep -B 1 'mOtherName'
The output :
mSomeName=SomeValue
mOtherName=OtherValue+Somethingelse
--
mSomeName=SomeValue2
mOtherName=OtherValue+Somethingelse2

Resources