I'm working on a script which checks if file exists. If it exists then I want to get the route.
What I did is the following:
RESULT_=$(find $PWD -name someRandom.json)
This returns the path to the file:
/Users/guest/workspace/random_repo/random/some_folder/someRandom.json
I'm stuck in the way to navigate among files. Is there a way of replacing someRandom.json with '' so I can do:
cd /Users/guest/workspace/random_repo/random/some_folder/
I tried using the solution provided here but it isn't working. I tried the following:
RESULT=$($RESULT/someRandom.json/'')
echo $RESULT
And this returns no such file or directory.
given:
$ echo "$result"
/Users/guest/workspace/random_repo/random/some_folder/someRandom.json
You can get the file name:
$ basename "$result"
someRandom.json
Or the path:
$ dirname "$result"
/Users/guest/workspace/random_repo/random/some_folder
Or you can use substring deletion:
$ echo "${result%/*}"
/Users/guest/workspace/random_repo/random/some_folder
Or, given the file name and the full path, just remove the file name:
$ echo "$tgt"
someRandom.json
$ echo "${result%"$tgt"}"
/Users/guest/workspace/random_repo/random/some_folder/
There are many examples of Bash string manipulation:
BashFAQ/100
BashFAQ/073
Bash Hacker's Parameter Expansion
Side note: Avoid using CAPITAL_NAMES for Bash variables. They are reserved for Bash use by convention...
You want parameter expansion, not command substitution.
RESULT="${RESULT%/*}/"
Related
I am running a shell script on my mac, and i am getting a "No Such file or directory.
The input is: the replacement_name, and the working dir.
The output is: changing all files in the directory from $file to $newfilename
#!/bin/sh
echo "-------------------------------------------------"
echo "Arguments:"
echo "Old File String: $1"
echo "New File Name Head: $2"
echo "Directory to Change: $3"
echo "-------------------------------------------------"
oldname="$1"
newname="$2"
abspath="$3"
echo "Updating all files in '$abspath' to $newname.{extension}"
for file in $(ls $abspath);
do
echo $file
echo $file | sed -e "s/$oldname/$newname/g"
newfilename=$("echo $file| sed -e \"s/$oldname/$newname/g\"")
echo "NEW FILE: $newfilename"
mv $abspath/$file $abspath/$newfilename
done
It seems that it doesnt like assigning the result of my 1-liner to a variable.
old_filename_string_template.dart
test_template.dart
./bulk_rename.sh: line 16: echo old_filename_string.dart| sed -e "s/old_filename_string/test/g": No such file or directory
NEW FILE:
Test Information:
mkdir /_temp_folder
touch old_filename_string_template.a old_filename_string_template.b old_filename_string_template.c old_filename_string1_template.a old_filename_string1_template.b old_filename_string1_template.c old_filename_string3_template.a old_filename_string3_template.b old_filename_string3_template.c
./convert.sh old_filename_string helloworld /_temp_folder
The double quotes here make the shell look for a command whose name (filename, alias, or function name) is the entire string between the quotes. Obviously, no such command exists.
> newfilename=$("echo $file| sed -e \"s/old_filename_string/$1/g\"")
Removing the double quotes inside the parentheses and the backslashes before the remaining ones will fix this particular error.
The construct $(command sequence) is called a command substitution; the shell effectively replaces this string with the standard output obtained by evaluating command sequence in a subshell.
Most of the rest of your script has much too few quotes; so it's really unclear why you added them here in particular. http://shellcheck.net/ is a useful service which will point out a few dozen more trivial errors. Briefly, anything which contains a file name should be between double quotes.
Try to put double quotes outside backticks/subtitutions (not INSIDE backticks/substitutions like $("..."))
newfilename="$(....)"
By the way, please consider to use the package perl rename which already does this bulk file rename very well, with Perl regex style which is easier to use. This perl rename command maybe alreay available in your (Mac) distro. See intro pages.
I was trying to delete a path from my PATH variable using the shell string manipulation approach: ${string%$substring}. It works for common variable but it doesn't work when I want to delete a path in PATH variable.
xiangxue➜~» echo $PATH [10:34:16]
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/xiangxue/anaconda2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin
Suppose I would like to delete :/usr/games entry from PATH, I did this:
xiangxue➜~» echo ${PATH%:/usr/games} [10:40:12]
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/home/xiangxue/anaconda2/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin
The PATH doesn't delete :/usr/games entry, and it looks exactly same.
The ${parameter%pattern} string manipulation removes from the end of the string (see the Bash Guide on Parameter Expansion or the Bash Reference manual or the POSIX Spec) but :/usr/games isn't at the end of your string so it doesn't match.
The expansion you want for this is the ${parameter/pat/string} expansion:
echo "${PATH/:\/usr\/games}"
Alternatively you want to split $PATH on : and loop to filter out your desired entry.
try this;
PATH=$(echo $PATH | sed 's/:\/usr\/games:/:/g;s/:\/usr\/games//g;s/\/usr\/games://g')
user#host:/tmp$ PATH=/usr/games:/usr/sbin:/usr/bin:/sbin:/usr/games:/bin:/usr/games
user#host:/tmp$ echo $PATH
/usr/games:/usr/sbin:/usr/bin:/sbin:/usr/games:/bin:/usr/games
user#host:/tmp$ PATH=$(echo $PATH | sed 's/:\/user\/games:/:/g;s/:\/usr\/games//g;s/\/usr\/games://g')
user#host:/tmp$ echo $PATH
/usr/sbin:/usr/bin:/sbin:/bin
I have an arbitrary path which contains the directory mydir:
/some/path/to/mydir/further/path/file.ext
I want to get the part after mydir, in this example:
/further/path/file.ext
Please note that the levels of subdirectories are also arbitrary, so a path like
/yet/another/long/path/to/mydir/file.ext
is also possible (where the result would be "file.ext")
The first occurrence of mydir should be used, so the path
/path/mydir/some/other/path/mydir/path/file.ext
should result in
/some/other/path/mydir/path/file.ext
How can one do this with bash?
Note. It is assumed that mydir will always appear enclosed between slashes.
after=${mydir#*/mydir/}
if [ "$mydir" = "$after" ]; then
fail_with_error "Path does not contain /mydir/"
fi
after="/$after"
In line 1, the # means substring after, and the * is the usual placeholder. To be safe against directories like .../mydirectaccess/... I included the slashes at both ends of mydir. Line 5 just prepends the slash that had been taken off by line 1.
Using Shell Parameter Expansion:
$ mydir="/some/path/to/mydir/further/path/file.ext"
$ echo ${mydir#*mydir}
/further/path/file.ext
$ mydir="/path/mydir/some/other/path/mydir/path/file.ext"
$ echo ${mydir#*mydir}
/some/other/path/mydir/path/file.ext
Go through sed. Example:
echo /some/path/to/mydir/further/path/file.ext | sed 's/.*mydir/mydir/'
Using bash, you can do something like this:
V=/yet/another/long/path/to/mydir/file.ext
R=${V#*mydir/}
echo $R
file.ext
How to made bash to execute variable value.
For example, we have this code, where variable value was set in single quotes(!).
#!/bin/bash
V_MY_PATH='$HOME'
echo "$V_MY_PATH"
ls $V_MY_PATH
The output is
$HOME
ls: $HOME: No such file or directory
How to made bash to translate shell variable insto its value if there is some.
I want to add some code after V_MY_PATH='$HOME' to make output like echo $HOME.
It's something simple, but i'm stuck.
(NB: I know that with V_MY_PATH="$HOME", it works fine.)
EDIT PART:
I just wanted to make it simple, but I feel that some details are needed.
I'm getting parameter from a file. This part works good. I don't want to rewite it.
The problem is that when my V_MY_PATH contains a predefined variable (like $home) it's not treated like its value.
Remove the single quotes
V_MY_PATH='$HOME'
should be
V_MY_PATH=$HOME
you want to use $HOME as a variable
you can't have variables in single quotes.
Complete script:
#!/bin/bash
V_MY_PATH=$HOME
echo "$V_MY_PATH"
ls "$V_MY_PATH" #; Add double quotes here in case you get weird filenames
Output:
/home/myuser
0
05430142.pdf
4
aiSearchFramework-7_10_2007-v0.1.rar
etc.
use variable indirect reference so:
pete.mccabe#jackfrog$ p='HOME'
pete.mccabe#jackfrog$ echo $p
HOME
pete.mccabe#jackfrog$ ls ${p}
ls: cannot access HOME: No such file or directory
pete.mccabe#jackfrog$ ls ${!p}
bash libpng-1.2.44-1.el6 python-hwdata squid
...
pete.mccabe#jackfrog$
The ${!p} means take the value of $p and that value is the name of the variable who's contents I wish to reference
Use eval command:
#!/bin/bash
V_MY_PATH='$HOME'
echo "$V_MY_PATH"
eval ls $V_MY_PATH
You can use single or double quotes, and in your case, none if you prefer.
You have nothing telling bash what the variable is equal to. Maybe something like this? (unless I misunderstand what you are trying to do)
======================================================================
#!/bin/bash
#########################
# VARIABLES #
#########################
V_MY_PATH=home
#########################
# SCRIPT #
#########################
echo "What is your home path?"
read $home
echo "Your home path is $V_MY_PATH"
ls $V_MY_PATH
Of course you could also just remove the variable at the top and use:
echo "Your home path is $home"
I want to make a script that takes a file path for argument, and cds into its folder.
Here is what I made :
#!/bin/bash
#remove the file name, and change every space into \space
shorter=`echo "$1" | sed 's/\/[^\/]*$//' | sed 's/\ /\\\ /g'`
echo $shorter
cd $shorter
I actually have 2 questions (I am a relative newbie to shell scripts) :
How could I make the cd "persistent" ? I want to put this script into /usr/bin, and then call it from wherever in the filesystem. Upon return of the script, I want to stay in the $shorter folder. Basically, if pwd was /usr/bin, I could make it by typing . script /my/path instead of ./script /my/path, but what if I am in an other folder ?
The second question is trickier. My script fails whenever there is a space in the given argument. Although $shorter is exactly what I want (for instance /home/jack/my\ folder/subfolder), cd fails whith the error /usr/bin/script : line 4 : cd: /home/jack/my\: no file or folder of this type. I think I have tried everything, using things like cd '$shorter' or cd "'"$shorter"'" doesn't help. What am I missing ??
Thanks a lot for your answers
in your .bashrc add the following line:
function shorter() { cd "${1%/*}"; }
% means remove the smaller pattern from the end
/* is the patern
Then in your terminal:
$ . ~/.bashrc # to refresh your bash configuration
$ type shorter # to check if your new function is available
shorter is a function
shorter ()
{
cd "${1%/*}"
}
$ shorter ./your/directory/filename # this will move to ./your/directory
The first part:
The change of directory won't be “persistent” beyond the lifetime of your script, because your script runs in a new shell process. You could, however, use a shell alias or a shell function. For example, you could embed the code in a shell function and define it in your .bash_profile or other source location.
mycdfunction () {
cd /blah/foo/"$1"
}
As for the “spaces in names” bit:
The general syntax for referring to a variable in Bourne shells is: "$var" — the "double quotes" tell the shell to expand any variables inside of them, but to group the outcome as a single parameter.
Omitting the double quotes around $var tells the shell to expand the variable, but then split the results into parameters (“words”) on whitespace. This is how the shell splits up parameters, normally.
Using 'single quotes' causes the shell to not expand any contents, but group the parameters togethers.
You can use \ (backslash-blank) to escape a space when you're typing (or in a script), but that's usually harder to read than using 'single quotes' or "double quotes"…
Note that the expansion phase includes: $variables wild?cards* {grouping,names}with-braces $(echo command substitution) and other effects.
| expansion | no expansion
-------------------------------------------------------
grouping | " " | ' '
splitting | (no punc.) | (not easily done)
For the first part, there is no need for the shorter variable at all. You can just do:
#!/bin/bash
cd "${1%/*}"
Explanation
Most shells, including bash, have what is called Parameter Expansion and they are very powerful and efficient as they allow you to manipulate variables nativly within the shell that would normally require a call to an external binary.
Two common examples of where you can use Parameter Expansion over an external call would be:
${var%/*} # replaces dirname
${var##*/} # replaces basename
See this FAQ on Parameter Expansion to learn more. In fact, while you're there might as well go over the whole FAQ
When you put your script inside /usr/bin you can call it anywhere. And to deal with whitespace in the shell just put the target between "" (but this doesn't matter !!).
Well here is a demo:
#!/bin/bash
#you can use dirname but that's not apropriate
#shorter=$(dirname $1)
#Use parameter expansion (too much better)
shorter=${1%/*}
echo $shorter
An alternate way to do it, since you have dirname on your Mac:
#!/bin/sh
cd "$(dirname "$1")"
Since you mentioned in the comments that you wanted to be able to drag files into a window and cd to them, you might want to make your script allow file or directory paths as arguments:
#!/bin/sh
[ -f "$1" ] && set "$(dirname "$1")" # convert a file to a directory
cd "$1"