sed or awk to append to specific line - bash

There is a file that I'd like to edit from a bash script
if [[ -n "$CHROME_USER_DATA_DIR" ]]; then
exec -a "$0" "$HERE/chrome" \
--user-data-dir="$CHROME_USER_DATA_DIR" "$#"
else
exec -a "$0" "$HERE/chrome" "$#"
fi
I would like to append to the end of any line containing exec -a "$0" "$HERE/chrome" "$#" the string
--user-data-dir
The result would over write the existing file with
if [[ -n "$CHROME_USER_DATA_DIR" ]]; then
exec -a "$0" "$HERE/chrome" \
--user-data-dir="$CHROME_USER_DATA_DIR" "$#"
else
exec -a "$0" "$HERE/chrome" "$#" --user-data-dir
fi
I am having difficulty understanding sed and awk, but want to make this work.

Unfortunately you need to use a regexp instead of a string comparison since your white space can apparently vary so that introduces some escaping complexity. Using GNU awk for -i inplace and \s shorthand for [[:space:]]:
awk -i inplace '/exec\s+-a\s+"\$0"\s+"\$HERE\/chrome"\s+"\$#"/{$0=$0 " --user-data-dir"} 1' file

Try this to edit your file with GNU sed:
sed -i '5s/$/& --user-data-dir/' file

With awk you could do:
awk 'NR==5{$0=$0" --user-data-dir"}1' file > newfile

Related

Multiple sub-string matches using process substitution

I want to do sub-string match within .sh file and extract list of cmds and append it an existing file.
So far I'm using perl -ne and it works with last-matched value shown on screen as
echo 'declare -a org_val=($(chkconfig --list autofs) $(grep "^PROMPT="/etc/sysconfig/init)' |
perl -pe 's|.*\$\((.*?)\)\s+|\1|g'
The following is the output of above command:
grep `"^PROMPT=" /etc/sysconfig/init`
I also want it to output
chkconfig --list autofs
What I did was write a small .sh to and save results of sed in array using command substitution below
#!/bin/bash
nl='\n'
declare -a array0
while IFS=$nl read -r line
do
array0+=$line
#echo $line
done < <( perl -pe 's|.*\$\((.*?)\)\s+|\1|g') < /tmp/sunny
echo "${array0[#]}"
The output of above is
declare -a org_val=($(chkconfig --list autofs) $(grep "^PROMPT=" /etc/sysconfig/init)
content of /tmp/sunny is
declare -a org_val=($(chkconfig --list autofs) $(grep "^PROMPT=" /etc/sysconfig/init) )
perl -nle'print for /\$\(([^)]*)\)/g'
Of course, that assumes that no ) exists within $(...).
With GNU awk for multi-char RS:
$ echo 'declare -a org_val=($(chkconfig --list autofs) $(grep "^PROMPT="/etc/sysconfig/init)' |
awk -v RS='[$][(][^()]+' 'RT{print substr(RT,3)}'
chkconfig --list autofs
grep "^PROMPT="/etc/sysconfig/init

Bash script support piping data into it

I have a bash script that I want to expand to support piping json into.
Example:
echo '{}' | myscript store
So, I tried the following:
local value="$1"
if [[ -z "$value" ]]; then
while read -r piped; do
value=$piped
done;
fi
Which works in a simple case above, but doing:
cat input.json | myscript store
Only get's the last line of the file input.json, it does not handle every line.
How can I support all cases of piping?
The following works:
if [[ -z "$value" && ! -t 0 ]]; then
while read -r piped; do
value+=$piped
done;
fi
The trick was using += and also checking ! -t 0 which checks if we are piping.
If you want to behave like cat, why not use it?
#! /bin/bash
value="$( cat "$#" )"

sed command garbled for bash 3.0

I have gone through other threads Sed command garbled didnt work
but it didn't helped me
flag=1
echo "enter the folder into which you want to capture"
read logs
mkdir $logs
path=/user/gur40139/shell/angel
for i in $path/*.tra*
do
value=$( grep -ic \*= $i )
if [ $value -ge $flag ]
then
name=`basename $i .tra\*`
echo -e "count is $value\n" >> $path/$logs/log_"$name".txt
sed -n '/\*=/ {n;p}' $i|sed 2n\;G >> $path/$logs/log_"$name".txt
fi
done
echo -e "\nDone\n"
Error:
sed: command garbled: /\*=/ {n;p}
Additional Note: This code is working properly on bash 4.1 version but I want to test it in 3.0, There many options which are not even working like sed --version.
sed -n '/\*=/ {n;p;}' ...
you need to terminate the line after the p so a ; or a new line. Your code will certainly work on recent GNU sed but not on posix version

Ubuntu BASH inotifywait to trigger another script

I am trying to use inotifywait within a bash script to monitor a directory for a file with a certain tag in it (*SDS.csv).
I also only want to execute once (once when the file is written to the directory data ).
example:
#! /bin/bash
inotifywait -m -e /home/adam/data | while read LINE
do
if [[ $LINE == *SDS.csv ]]; then
./another_script.sh
fi
done
While this may not be the ideal solution, it may do the trick:
#! /bin/bash
while true
do
FNAME="$(inotifywait -e close_write /home/adam/data | awk '{ print $NF }')"
if [ -f "/home/adam/data/$FNAME" ]
then
if grep -q 'SDS.csv' "/home/adam/data/$FNAME"
then
./another_script.sh
fi
done
done

Replace script works if I type manually but not in script

I have a bash script, replace.sh with the following contents:
ack-grep -a -l -i --print0 --text "$1" | xargs -0 -n 1 sed -i -e 's/$1/$2/g'
When I try and run it as, eg:
replace.sh something somethingnew
The prompt returns without errors but no changes have been made to any files.
If I manually type:
ack-grep -a -l -i --print0 --text "something" | xargs -0 -n 1 sed -i -e 's/something/somethingelse/g'
The files get changed as expected.
Ths $1 syntax seems to work for other scripts I've written. I'm guessing I'm missing something to do with escaping the args or something?
Thanks!
Ludo.
Variable substitutions aren't done in single quotes, try:
ack-grep -a -l -i --print0 --text "$1" | xargs -0 -n 1 sed -i -e "s/$1/$2/g"
See the bash man page section on QUOTING.
Use "" instead of '' in the sed expression. It will not prevent the variablename-resolving. What you are actually doing now is replacing $1 to $2. You can test in console (without writing a script) like this:
$ a=something
$ b=somethingelse
$ sed 's/$a/$b/g' testfile
$ sed "s/$a/$b/g" testfile
This isn't related to your question, but some help on using ack.
The -a and --text conflict with each other. -a will give you a superset of --text. Use one or the other.
Also, it looks like you might as well use grep -Z instead of ack since you're not using any of ack's functionality that is a superset of grep.
In general, if you're using ack in a pipeline, you should probably be using good ol' grep instead.

Resources