Bash removing path from path variable and sed command - bash

Working with this code
What is the most elegant way to remove a path from the $PATH variable in Bash?
export PATH=`echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}'` | sed 's/:*$//'
In this instance if I run just the:
export PATH=`echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}'`
I can get the path containing /SDE/ removed; however a : remains. The sed command after I am assuming should remove that. When I run this entire command at once nothing gets removed at all. What is wrong with the sed statement that is causing the path not to update and how can I make the sed command remove the colon : after the /SDE/ path variable is removed.

The problem is the placement of the closing back-quote ` in the command:
export PATH=`echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}'` | sed 's/:*$//'
If you used the recommended $(...) notation, you'd see that this is equivalent to:
export PATH=$(echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}') | sed 's/:*$//'
which pipes the output of the export operation to sed, but export is silent.
Use:
export PATH=$(echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}' | sed 's/:*$//')
I have fixed the answer from which the erroneous command was copied verbatim. As tripleee notes in a comment, I'm not wholly convinced by the awk solution, but the question was 'what was wrong with the code' and the answer is 'where the back-quotes are placed'. The awk script does handle removing elements of a PATH at any position in the PATH; the sed script simply ensures there is no trailing : so that there is no implicit use of the current directory at the end of the PATH.
See also: How do I manipulate PATH elements in shell scripts and the clnpath script at How to keep from duplicating PATH variable in csh — the script is for POSIX-ish shells like the Bourne, Korn, Bash shells, despite the question's subject. One difference between clnpath and the notation used here is that clnpath only removes full pathnames; it does not attempt to do partial path element matching:
export PATH=$(clnpath $PATH /opt/SDE/bin)
if the path element to be removed was /opt/SDE/bin. Note that clnpath can be used to maintain LD_LIBRARY_PATH, CDPATH, MANPATH and any other path-like variable; so can the awk invocation, of course.
I note in passing that that the /SDE/ pattern in the awk script will remove /opt/USDER/bin; the slashes in the regex have nothing to do with slashes in the pathname.

$ PATH="$( awk -v rmv="/SDE/" -v path="$PATH" 'BEGIN{sub(rmv,"",path); gsub(/:+/,":",path); print path}' )"
The above is a guess since you didn't provide sample input or expected output so it may not be quite what you want but it is the right approach.

Just in bash:
tmp=":$PATH"
[[ $tmp =~ :[^:]*/SDE/[^:]* ]] && tmp=${tmp/${BASH_REMATCH[0]}/}
PATH=${tmp#:}

Related

How to remove the username/hostname line from an output on Korn Shell?

I run the command
df -gP /data1 /data2 | grep -v File | awk '{print $1}' |
awk -F/dev/ '$0=$2' | tr '\n' '
on the AIX shell (ksh) and it prints the output below:
lv_data01 lv_data02 root#testhost:/
However, I would like the output to be printed this way. Could someone help?
lv_data01 lv_data02
Using grep … | awk … | awk … is not necessary; a single awk could do the whole job. So could sed and it might even be easier. I'd be tempted to deal with the spacing by using:
x=$(df … | sed …); echo $x
The tr command, once corrected, replaces newlines with spaces, so the prompt follows without a newline before it. The ; echo suggestion adds the missing newline; the echo $x suggestion (note no double quotes) does too.
As for the sed command:
sed -n '/File/!{ s/[[:space:]].*//; s%^.*/dev/%%p; }'
Don't print anything by default
If the line doesn't match File (doing the work of grep -v):
remove the first space (blank or tab) and everything after it (doing the work of awk '{print $1}')
replace everything up to /dev/ with nothing and print (doing the work of awk -F/dev/ '{$0=$2}')
The command substitution and capture, followed by echo, deals with spaces and newlines.
So, my suggested solution is:
x=$(df -gP /data1 /data2 | sed -n '/File/!{ s/[[:space:]].*//; s%^.*/dev/%%p; }'); echo $x
You could add unset x after the echo if you are going to be using this directly in the shell and not in a shell script. If it'll be encapsulated in a shell script, you don't have to worry about it.
I'm blithely assuming the output from df -gP won't contain a path such as this, with two occurrences of /dev:
/who/knows/dev/lv_data01/dev/bin
If that's a real problem, you can fix the sed script, but I don't think it will be. It's one thing the second awk script in the question handles differently.

BASH: parse a variable with awk

I have a variable that contains the result of the command whereis ls which is:
ls: /bin/ls /usr/share/man/man1/ls.1.gz
I need to search through this variable and retrieve this specific portion and save it into a new variable, newVar:
/bin
I have tried echo $var | awk '{print $2}'
but this grabs /bin/ls
I then need to search through my $PATH variable finding the substring /bin: (I was thinking with my newVar as a match somehow) and somehow remove this portion of $PATH and update $PATH to reflect that change.
Quite new to bash scripting and any help would be greatly appreciated.
You might just use dirname and which:
dirname "$(which ls)"
You may use this awk:
whereis ls | awk '{sub(/\/ls$/, "", $2); print $2}'
sub function strips trailing /ls from 2nd column of whereis output.
$ echo "$var" | cut -d/ -f2
bin

How to parse variable to sed command in shell?

I have some variables:
$begin=10
$end=20
how to pass them to sed command.
sed -n '$begin,$endp' filename | grep word
sed -n '10,20p' filename | grep word
The reason this doesn't work is that single quotes in shell code prevent variable expansion. The good way is to use awk:
awk -v begin="$begin" -v end="$end" 'NR == begin, NR == end' filename
It is possible with sed if you use double quotes (in which shell variables are expanded):
sed -n "$begin,$end p" filename
However, this is subject to code injection vulnerabilities because sed cannot distinguish between code and data this way (unlike the awk code above). If a user manages to set, say, end="20 e rm -Rf /;", unpleasant things can happen.

BASH - add prefix (file path) to each line in text file using awk

I am trying to get the full path of a files within a directory. So far this is what I have in bash.
prefix="s3://${s3_bucket}/${s3_folder}/$(date --date="$i days ago" +"%Y/%m/%d")/"
#echo $prefix
aws s3 ls s3://${s3_bucket}/${s3_folder}/$(date --date="$i days ago" +"%Y/%m/%d")/ | sed -n 's/.*\([0-9][0-9]-h.*gz\)/\1/p' | awk '$0="${prefix}"$0' >> ${s3_files_1}
In my output, I am getting the following:
${prefix}file1.gz
${prefix}file2.gz
The output I am looking for is something like below.
s3://my_bucket/my_folder/file1.gz
s3://my_bucket/my_folder/file2.gz
My issue is with the way the awk command is interpreting the variable ${prefix}. Can anyone please help?
You can use -v to pass shell variable contents to awk:
prefix="s3://my_bucket/my_folder/"
echo "file1.gz" | awk -v myprefix="${prefix//\\/\\\\}" '{ print myprefix $0 }'
Sadly, awk -v is not data safe. This example uses parameter expansion to escape backslashes to avoid them being mangled.

Shell scripting and using backslashes with back-ticks?

I'm trying to do some manipulation with Wordpress and I'm trying to write a script for it...
# cat /usr/local/uftwf/_wr.sh
#!/bin/sh
# $Id$
#
table_prefix=`grep ^\$table_prefix wp-config.php | awk -F\' '{print $2}'`
echo $table_prefix
#
Yet I'm getting following output
# /usr/local/uftwf/_wr.sh
ABSPATH ABSPATH wp-settings.php_KEY LOGGED_IN_KEY NONCE_KEY AUTH_SALT SECURE_AUTH_SALT LOGGED_IN_SALT NONCE_SALT wp_0zw2h5_ de_DE WPLANG WP_DEBUG s all, stop editing! Happy blogging. */
#
Running from command line, I get the correct output that I'm looking for:
# grep ^\$table_prefix wp-config.php | awk -F\' '{print $2}'
wp_0zw2h5_
#
What is going wrong in the script?
The problem is the grep command:
table_prefix=`grep ^\$table_prefix wp-config.php | awk -F\' '{print $2}'`
It either needs three backslashes - not one - or you need to use single quotes (which is much simpler):
table_prefix=$(grep '^$table_prefix' wp-config.php | awk -F"'" '{print $2}')
It's also worth using the $( ... ) notation in general.
The trouble is that the backquotes removes the backslash, so the shell variable is evaluated, and what's passed to grep is, most likely, just ^, and each line starts with a beginning of line.
This has all the appearance as though the grep is not omitting all the lines that are not matching, when you issue the echo $table_prefix without quotes it collapses all the white space into a single output line, if you issue an: echo "$table_prefix", you would see the match with all the other white-space that was output.
I'd recommend the following sed expression instead:
table_prefix=$(sed -n "s/^\$table_prefix.*'\([^']*\)'.*/\1/p" wp-config.php)
You should try
#!/bin/sh
table_prefix=$(awk -F"'" '/^\$table_prefix/{print $2}' wp-config.php)
echo $table_prefix
Does this one work for you?
awk -F\' '/^\$table_prefix/ {print $2}' wp-config.php
Update
If you are using shell scripting, there is no need to call up awk, grep:
#!/bin/sh
while read varName op varValue theRest
do
if [ "_$varName" = "_\$table_prefix" ]
then
table_prefix=${varValue//\'/} # Remove the single quotes
table_prefix=${table_prefix/;/} # Remove the semicolon
break
fi
done < wp-config.php
echo "Found: $table_prefix"

Resources