I am writing a shell script in which I have to separate the file name and file path from a complete file path. For example /home/loneranger/Documents/test/file.dat is the complete path. I want to separate name and Path and put them in variables. So far I am able to separate file name by using basename command.
file_name =$(basename $path)
file_location =`echo $path | sed 's/$file_name//' `
But the sed command is not working. It's working when I execute it outside in command line by replacing the file_name by file.dat. Not sure why it's behaving this way. Can somebody explain.
PS: Sorry for poor formatting as I am typing from a mobile device.
the tool dirname does what you want:
file_name=$(basename $path)
file_location=$(dirname $path)
the sed command is not working because bash does not expand variables inside single quotes.
sed 's/$file_name//'
^ single quote
^ variable inside single quote not expanded
either use double quotes or open the single quotes around the variable:
sed "s/$file_name//"
sed 's/'$file_name'//'
but as said the tool dirname does what you want.
also note that you may not put spaces around the equal sign in the variable assignment
file_name =$(basename $path)
^ there should be no space here
the line above does not assign the result of basename to the variable file_name. instead it will try to execute the command file_name with one parameter which is the result of basename.
file_name=$(basename $path)
^ no space here
this line will define the variable.
It isn't working because you use $file_name in simple quote ('). Use double quotes " for enable variable translation.
file_location =`echo $path | sed "s/$file_name//"
Related
I am working on a script that involves paths with wildcards. I know the wildcards will match one file only, I just don't know what the file extension will be ahead of time so I am using a wildcard.
The goal here is to find the path to the appropriate file, and then add that path to line 16 of a script.
I have something like this:
path=/path/to/somewhere/fileName*
sed "16 a file=$path" myScript.sh
What I expect to get is this (on line 16):
file=/path/to/somewhere/fileName.extension
But what I get is:
file=/path/to/somewhere/fileName*
For some reason sed is not expanding the wildcard when it adds the contents of $path and I can't figure out how to make sed do such a thing. I'm looking for a solution that either a) has sed properly expand $path or b) a way to get $path to contain the fully expanded string before being passed to sed.
Your variable contains just a string and you then interpolate that string. sed can't know that's not what you mean. If you want the shell (not sed!) to expand the wildcard, probably use a loop.
for path in /path/to/somewhere/fileName*; do
if [ -e "$path" ]; then # handle wildcard possibly not matching
sed "16 a file=$path" myScript.sh
fi
done
It's unclear what should happen if the wildcard matches multiple files; perhaps you want to add a break before fi to only substitute the first one if that happens.
This might work for you (GNU sed, echo and bash):
export path='/path/toSomeWhere/filename*'
sed '16{s/$/\na file=$(echo $path)/;s/.*/echo "&"/e}' file
Export the variable path which has been set to /path/toSomeWhere/filename* (notice the single quotes which prevents interpolation).
On line 16 of file append a line a file=$(echo $path) and then surround both lines by double quotes and prepend the echo command and evaluate (the e flag on the second substitution command) the expression.
Alternative:
sed '17e echo "a file=$(echo /path/toSomeWhere/filename*)"' file
I have a path like this:
dirname=../2Reconnaissance-annoted/J39/IMG_2208.json
I want to get a new path by replacing ".json" with "_json", so I tried this command:
tr "\.json" "_json" <<<$dirname
The problem is that I get:
__/2Reconnaissance-annoted/J39/IMG_2208_json
Rather than
../2Reconnaissance-annoted/J39/IMG_2208_json
How do you fix it, please?
tr does transliteration, i.e. it replaces a character by a character, not a string by a string. What you need is substitution.
Most shells support substitution directly:
dirname=${dirname/.json/_json}
(${dirname/%.json/_json} would only substitute the substrings at the end of the string).
If your shell doesn't support it, you can use sed:
echo "$dirname" | sed -e 's/\.json$/_json/'
I have a file containing contents like:
aaaaaaaaaa
export ORACLE_HOME=/home/oracle/test/prod/db_1
bbbbbbbbbb
Now I want to replace the line of
export ORACLE_HOME=/home/oracle/test/prod/db_1
with something like below:
export ORACLE_HOME=/u01/app/oracle/product/11204/dbhome_1
I tried numerous ways found through Google like using "sed" or "awk" but neither one worked. I tried:
export D1="export ORACLE_HOME=/u01/app/oracle/product/11204/dbhome_1"
sed -i -e "s+export ORACLE_HOME=/home/oracle/test/prod/db_1+$D1+" file.lst
Note: as one Google search says, since the strings contains "/", so a different delimiter like "+" needs to be used.
Can you share with me the right command to do so?
sed -r 's~(ORACLE_HOME=).*~\1new/path/here~'
here ~ is used as the delimiter. If the new path is a bash variable, you can escape the quotes
sed -r 's~(ORACLE_HOME=).*~\1'$D1'~'
If you are still having trouble with the substitution, you can use this variation which will explicitly find the line containing export ORACLE_HOME before attempting the path substitution. The expression makes use of alternate delimiters for the substitution '|'.
To edit in place (Linux), you can use the '-i' option (and add '-i.bak' to make a backup of the original). If you are using a mac or other OS without the '-i' option available, use redirection to create a new file which you can copy over the current file.
sed -i '/^export\sORACLE_HOME/s|=.*$|=/u01/app/oracle/product/11204/dbhome_1|' \
yourfilename
or without '-i':
sed '/^export\sORACLE_HOME/s|=.*$|=/u01/app/oracle/product/11204/dbhome_1|' \
yourfilename > newfilename
cp yourfilename yourfilename.sav && mv -f newfilename yourfilename
(note: the '\' at the end of the sed command line is a simple line-continuation)
Using a Variable for Replacement
From your comment, if you want to use a variable instead of a hardcoded path for the replacement string, then simply replace the single-quotes with double-quotes and include the variable as the replacement string. For example:
npath=/u01/app/oracle/product/11204/dbhome_1
sed -i "/^export\sORACLE_HOME/s|=.*$|=$npath|" dat/opath.txt
I want to modify the include_path directive in my php.ini file using sed. Below, I've got a command that looks for a string and places the directive on a line after the match. However, I cannot get it to work while still maintaining the double quotes within the ${install_path} variable. The double quotes must be there.
The file I want to edit is php.ini. Here are a few lines before and after my target, which is the line right after "UNIX: ":
;;;;;;;;;;;;;;;;;;;;;;;;;
; Paths and Directories ;
;;;;;;;;;;;;;;;;;;;;;;;;;
; UNIX: "/path1:/path2"
;include_path = "/path1:/path2"
;
; Windows: "\path1;\path2"
install_path is defined as:
install_path="/var/www/mainapp"
And the sed command I am using below searches for a string match and then creates a new line right below it:
sed -i '/; UNIX: "\/path1:\/path2"/a include_path = "${install_path}/lib"' /etc/php.ini
The expected output within php.ini is:
; UNIX: "/path1:/path2"
include_path = "/var/www/mainapp/lib"
Where the include_path line has been created right after the line "; UNIX:..."
Thanks for your help.
Your main problem is dancing around the quoting conventions of the shell while preserving the quotes in the file.
You say you've defined install_path="/var/www/mainapp"; note that the quotes were removed by the shell so the string contains no quotes. That's important below. Compare the old and the new:
Old:
sed -i '/; UNIX: "\/path1:\/path2"/a include_path = "${install_path}/lib"' /etc/php.ini
New:
sed -i '/; UNIX: "\/path1:\/path2"/a include_path = "'"${install_path}/lib"'"' /etc/php.ini
Eh what? You've correctly enclosed your script in single quotes, but that prevents the shell from expanding ${install_path}. So, you have to terminate the single-quoted string, but you want double quotes in the output, so I placed the single quote after the double quote. Then I wrapped the value in ${install_path} in double quotes too: "${install_path}/lib". The double quotes are not crucial for the value you quote, but in general it is a good idea to use them. I then resume the single-quoting, and the first character is the closing double quote for the include path string in the .ini file, and then close the single quoted string. Yes, there are other ways you could write that last bit, but it would take considerable persuasion to convince me that alternatives using backslashes are better.
If you actually had preserved the double quotes around the install path value:
install_path='"/var/www/mainapp"'
you could use:
sed -i '/; UNIX: "\/path1:\/path2"/a include_path = '"${install_path}/lib" /etc/php.ini
Also note that only GNU sed allows you to put 'appended text' on the same line as the a command. POSIX sed does not, and other variants of sed on other platforms will not. For instance, on Mac OS X, you'd have to write:
sed -i '/; UNIX: "\/path1:\/path2"/a\
include_path = '"${install_path}/lib" /etc/php.ini
sed is for simple substitutions on individual lines, that is all. For anything even slightly more interesting you should be using awk. Chances are you want something like this:
awk -v install_path="$install_path" '
{ print }
/; UNIX: "\/path1:\/path2"/ { printf "include_path = \"%s/lib\"\n", install_path }
' /etc/php.ini
but without sample input and expected output it's a guess. To replace the contents of the original file just add > tmp && mv tmp /etc/php.ini to the end or use -i inplace up front with GNU awk.
In a file (file1.txt) I have /path1/|value1 (a path, followed by a value). I need to find the line containing that (unique) path and then change the value. So the line should end up as: /path1/|value2.
The challenge is that the /path1/, value1 and value2 parts are both contained within variables.
When I don't use a variable, I can use (thanks to this page):
sed '/path1/s/value1/value2/g' file1.txt > copyfile1.txt
(This creates a copy of the original file which I can later overwrite the original file using mv.)
This is just searching for path1. To search for /path1/ I can use:
sed '/\/path1\//s/value1/value2/g' file1.txt > copyfile1.txt
Using the answers to this question about extracting a substring I can put the /path1/, value1 and value2 parts into variables.
So my current code is:
sed '/'"${PATH}"'/s/'"${PREVIOUS_VALUE}"'/'"${NEW_VALUE}"'/g' file1.txt > copyfile1.txt
But this does not work because the PATH variable contains forward slashes. Using information from here I have tried first doing a substitution like this:
FORMATTED_PATH=$(echo "${PATH}" | sed 's/\//\/\//g')
first, and then used FORMATTED_PATH instead of PATH but then the find and replace does not work (no error messages, new file is empty). And in the logging FORMATTED_PATH = //path1// (which I think is correct).
How can I do this find and replace using variables containing forward slashes?
(I found out via this answer that I needed to close the single quote, use double quotes around the variable and then open the single quote again. But this does not help with the forward slashes.)
The code was so nearly right. Instead of:
FORMATTED_PATH=$(echo "${PATH}" | sed 's/\//\/\//g')
I should have had:
FORMATTED_PATH=$(echo "${PATH}" | sed 's/\//\\\//g')
This then produces the correct logging of: FORMATTED_PATH = \/path1\/
awk will work too:
awk -F '|' -v path="$paht" -v new="$new_value" '{
if ($1 == path) {print path FS new}
else {print}
}' file1.txt > copyfile1.txt
Also, don't use all-caps for your shell variables: you have wiped out your shell's PATH variable used to find programs..
Usually the sed's s command (as in s///) supports using separators other than /. For example:
$ echo '/path1/|value1' | sed 's,\(/path1/|\).*,\1value2,'
/path1/|value2
$
This is very convenient when dealing with file pathnames which include / chars.