I need to modify a number into a file using a bash script
I want to remove a line that contains dalvik.vm.heapsize=256 and replace it with a new line that contains dalvik.vm.heapsize=512. I not know the line number and 256 is an ipotetic value. How I can build a script that perform this action??
Use the sed command:
sed -i -e 's/^\(dalvik.vm.heapsize=\).*/\1512/' build.prop
The command searches for a line starting with dalvik.vm.heapsize=, then replaces the part after = with 512. The left part is captured using the regular expression group, and \1 in the replacement part (\1512) refers to this group. The -i option instructs to replace in-place. Refer to info sed for details.
Here is a more advanced example taking into account possible leading spaces/tabs and making the match stricter by means of the regular expression lists:
sed -i -e 's/^\([ \t]*dalvik.vm.heapsize=\)[0-9]\+/\1512/' build.prop
Perl is more flexible. I prefer to use it for more complicated tasks. There is no such simple way as sed's -i option for Perl, however; but you can simply use the shell redirection, e.g.:
cat build.prop | \
perl -n -e 's/^([\t\s]*dalvik.vm.heapsize=)\d+/${1}512/; print' > build.prop
Related
I'm writing a simple Bash script that simply the call of HadnBrakeCli for render videos.
I also implemented a simple queue option: the queue file just store the line-command it has to call to start a render.
So I wrote a while-loop to read one line at time, eval $line and repeat untill file ends.
if [[ ${QUEUE_MODE} = 'RUN' ]]; then
QUEUE_LEN=`cat ${CONFIG_DIR}/queue | wc -l`
QUEUE_POS='1'
printf "Queue lenght:\t ${QUEUE_LEN}\n"
while IFS= read line; do
echo "--Running render ${QUEUE_POS} on ${QUEUE_LEN}..."
echo "++" && echo "$line" && echo "++"
eval "${line}"
tail -n +2 "${CONFIG_DIR}/queue" > "${CONFIG_DIR}/queue.tmp" && mv "${CONFIG_DIR}/queue.tmp" "${CONFIG_DIR}/queue"
echo "--Render ended"
QUEUE_POS=`expr $QUEUE_POS + 1`
done < "${CONFIG_DIR}/queue"
exit 0
The problem is that any command makes the loop to work fine (empty line, echo "test"...), but as soon a proper render is loaded, it is launched and finished correctly, but also the loops exists.
I am a newbie so I tried some minor changes to see what effect I got, but nothing change the result.
I commented the command tail -n +2 "${CONFIG_DIR}/queue" > "${CONFIG_DIR}/queue.tmp" && mv "${CONFIG_DIR}/queue.tmp" "${CONFIG_DIR}/queue" or I added/removed IFS= in the while-loop or removed the -r in read command.
Sorry if the question is trivial, but I'm really missing some major part in how it works, so I have no idea even how to search for the solution.
I'll put a sample of a general render in the queue file.
HandBrakeCLI -i "/home/andrea/Videos/done/Rap dottor male e mini me.mp4" -o "/hdd/Render/Output/Rap dottor male e mini me.mkv" -e x265 -q 23 --encoder-preset faster --all-audio -E av_aac -6 dpl2 --all-subtitles -x pmode:pools='16' --verbose=0 2>/dev/null
HandBrakeCLI reads from standard input, which steals the rest of the queue file before read line can see it. My favorite solution to this is to pass the file over something other than standard input, like file descriptor #3:
...
while IFS= read line <&3; do # The <&3 makes it read from FD #3
...
done 3< "${CONFIG_DIR}/queue" # The 3< redirects the file into FD #3
Another way to avoid the problem is to redirect input to the HandBrakeCLI command:
...
eval "${line}" </dev/null
...
There's some more info about this in BashFAQ #89: I'm reading a file line by line and running ssh or ffmpeg, only the first line gets processed!
Also, I'm not sure I trust the way you're using tail to remove lines from the queue file as they're executed. I'm not sure it's really wrong, it just looks fragile to me. Also, I'd recommend using lower- or mixed-case variable names, since there are a bunch of all-caps names with special meanings, and re-using one of them by mistake can have weird consequences. Finally, I'd recommend running your script through shellcheck.net, as it'll make some other good recommendations.
[BTW, this question is a duplicate of "Bash script do loop exiting early", but that doesn't have any upvoted or accepted answers.]
Using adb shell to run commands on an android device, I get different results when running ls with or without a wildcard ( globbing, i.e * ).
When running ls without a wildcard, the last path is displayed properly. When running ls with a wildcard, the path is displayed with an : in the end of it for some reason. The actual file does not have a : in its path.
My issue is specifically with the last file: /data/data/com.kauf.wrapmyFaceFunphotoeditor/files/DV-com.com.kauf.wrapmyFaceFunphotoeditor-2020-05-17-17-44-30-DEBUG.txt:
it has an : in the end which isn't supposed to be there
Why does using a wildcard in ls add characters to the result path?
Edit, environment details: Windows 10 / Android 7, the code is running on sh. I've ran adb shell to get to this command prompt, and doing it in one line (i.e adb shell su -c ls ...) returns similar results, same for adb shell command ...; also clarified the question.
As described in Why you shouldn't parse the output of ls, ls's behavior is not always well-defined. It's generally safer to use NULs (if you don't have any control or knowledge of filenames) or newlines (if you have reason to be certain that filenames can't contain them) to directly delimit a list of values emitted by the shell. Consider, then:
# output is separated by NULs, which cannot possibly exist in filenames
printf '%s\0' /data/data/com.kauf.wrapmyfacefunphotoeditor/files/DV-*
...or...
# output is separated by newlines; beware of a file named DV-evil<newline>something-else
printf '%s\n' /data/data/com.kauf.wrapmyfacefunphotoeditor/files/DV-*
Note that if you're passing this through extra unescaping layers, it may be necessary to double up your backslashes -- if you see literal 0s or ns separating filenames in your output, that's evidence of same.
Note also that if no matching files exist, a glob will expand to itself, so you can get an output that contains only the literal string /data/data/com.kauf.wrapmyfacefunphotoeditor/files/DV-*; in bash this can be suppressed with shopt -s nullglob, but with /bin/sh (particularly the minimal busybox versions more likely to be available on Android) this may not be available. One way to work around this is with code similar to the following:
# set list of files into $1, $2, etc
set -- /data/data/com.kauf.wrapmyfacefunphotoeditor/files/DV-*
# exit immediately if $1 does not exist
if [ "$#" -le 1 ] && [ ! -e "$1" ]; then
exit
fi
# otherwise, print the list in our desired format
printf '%s\0' "$#"
i'm writing a shell script for android and i need to get the last created directory, i would usually use
ls -t | head -1 but ls -t gives me the error "ls: Unknown option '-t'"
is there another shell command that can order the files by time-stamp or another way to do that in android? the busy box is more limited
It looks like stat is available in BusyBox, which means that you could do something like this:
stat -c '%Y %n' */ | sort -nr | cut -d' ' -f2-
This passes the names of all directories (paths ending in a slash) to stat, which prints the last modification time (seconds since the UNIX epoch) and the filename. These are sorted in reverse numerical order and then the time field is stripped from each line.
This assumes that your directory names don't contain newlines, otherwise the sorting would be messed up.
I have a shell script like this :
sed -i '/^###########/,/^#End of Build.Prop/d' /system/build.prop;
#
sed -i '/^#Start Build.Prop Tweak/,/^#End of Build.Prop Tweak/d' /system/build.prop;
#
sed -i '/^#Start Build.Prop Tweak/,/^ro\.config\.hwfeature_wakeupkey=0/d' /system/build.prop;
Of the three Shell Commands stated above none of them works when put in a sh file. But, if I use a TerminalEmulator, the three scripts can be executed
I want to use the scripts in an Android Device
No, it is too dangerous.
When the end-search tag is missing, you will delete a large part of your file.
When you want to delete the first and second line in a file, it seems working ok:
$ cat test.txt
first line
second line
third line
$ cat test.txt | sed '/first/,/second/ d'
third line
EDIT: One command less with sed '/first/,/second/ d' test.txt
But what happens when the second line can not be found?
Your sed command should skip removing lines, but it will:
$ cat test.txt | sed '/first/,/mistake/ d'
$
EDIT: One command less with sed '/first/,/mistake/ d' test.txt
All lines from the first match have been deleted !
Right now I am using rm -r /blaa/* to delete all folders and files in the blaa directory. What I am looking for is a way to remove all folders and files in the blaa directory except if the folder is named abc.
Any ideas?
In Linux:
There are many ways to this; however I believe the best way to do this is to simply use the "find" tool.
find ! -iname "abc" -exec rm -rf {} \;
We can easily find and delete the every file and folder that is not named "abc".
find - to find files
! -iname - to filter files/folders, the "!" means not
-exec - to execute a command on every file
rm -rf - remove/delete files -r for folders as well and -f for force
"{} \;" - allows the commands to be used on every file
In Android:
Since you can't use "rm -rf" and when you use "rm -r" it will delete the folder "." which ends up deleting everything.
I am guessing you have "root" on your phone because you can use the "find" tool.
find ! -iname "abc" | sed 1d | xargs rm -r
find - to find files
! -iname - to filter files/folders, the "!" means not
| - pipe sends data to next command
sed - replace text/output
"1d" - removes first line when you do "find ! -iname" by itself
xargs - runs commands after pipe
rm -r - remove/delete files, "-r" for recursive for folders
Edit: Fixed and tested in Android
You can easily change this to suite your needs, please let me know if this helps!
The Adopted Solution
...and the final hoorah... This is what worked for the use case (helps to sum up the comments below as well):
find ! -iname "abc" -maxdepth 1 -depth -print0 | sed '$d' | xargs -0 rm -r;
Notes:
-depth — reverses the output (so you dont delete sub-dirs first
-maxdepth 1 — kind of voids the use of -depth, but hey... this says only output contents of the current directory and not sub-dirs (which are removed by the -r option anyway)
-print0 and -0 — splits on line feeds instead of white space (for dirs with space in the name)
sed "$d" — says to remove the last line (cause its now reversed). The last line is just a period which including would make the call delete everything in the directory (and subs!)
I am sure someone can tighten this up, but it works and was a great learning op!
Thanks again to Jared Burrows(and the Unix community in general — go team!) — MindWire