I am using a find statement to execute python scripts which are in sub folders of all sub folders of the current directory
The find statement is find . -name \process.py -type f -exec python3 {} \;
The problem I am encountering is that the script is using relative paths e.g ..\data for retrieving other resources. These relative paths are resolved as required when the script is executed individually by running it from its directory but when running the script from a parent directory two levels up using the find command the path resolves relative to that parent directory causing errors
You can use -execdir option of the find command:
Having the following folder structure in /tmp:
/test
/test/subdir1
/test/subdir1/subdir2
/test/subdir1/subdir2/subdir3
and a r.py file in each folder:
# r.py
import os
dirpath = os.path.dirname(os.path.realpath(__file__))
print(dirpath)
You have the output:
/tmp/test
/tmp/test/subdir1
/tmp/test/subdir1/subdir2
/tmp/test/subdir1/subdir2/subdir3
If you need to do this in python I suggest looking at this answer:
How to get an absolute file path in Python
It is always better to find an absolute path, If using bash:
readlink -f filename
Related
I have a c5 project with a directory C5PROJECTDIR it has a bin directory. Is there a way (without adding C5PROJECTDIR/bin to $PATH) to access commands from any other subdirectory of C5PROJECTDIR?
For example:
There is an x command located here: C5PROJECTDIR/bin/x.
I want to run this command from a bash script from C5PROJECTDIR/packages/some-other-dir.
UPDATE: The sub directory can be more or less deeper in the tree...
How can it be possible?
There are a few ways:
Use relative paths:
Essentially call the binary directly with its path, but relative to the current script. If your script is located in /home/user/foo/C5PROJECTDIR/packages/somedir/script, then you call the script relatively:
#!/usr/bin/env bash
../../bin/x
The problem with this method is maintainability. Imagine you want to move your script to /home/user/foo/C5PROJECTDIR/packages/scripts, then you would have to update all your scripts.
Use a shell variable:
Instead of relative paths, you can define a variable PROJECTHOME which contains the base value.
#!/usr/bin/env bash
PROJECTHOME=/home/user/foo/C5PROJECTDIR
$PROJECTHOME/bin/x
This generally solves most problems unless you move project location from /home/user/foo/C5PROJECTDIR to /home/user/random-dir. But this can be solved with a simple sed command that searches for the line /home/user/foo/C5PROJECTDIR and replaces it.
PATH variable only make things easier.
You able to run any commands with absolute path like /bin/echo or /home/jon/myscript. Relative path works as well ~/../../bin/ls.
Script have its own PATH variable, so you can add the desired location to PATH in your script if you like.
Apart from this you have to deal with permissions.
The user that have script executed by, must have execute permission on the x script.
To find and execute command:
find C5PROJECTDIR -type f -executable -name "x" -exec {} \;
Find's must be strict to match only one command else it will execute all that it fund. You cannot have script with the same name under C5PROJECTDIR in this case.
From security point of view. I do not recommend this, as anyone can put an executable file under C5PROJECTDIR with a name used in the script. things can go nasty.
I want to use the find command to execute a special command on all of the files inside the directory that are contained inside multiple different directories with a specific keyword in it (the keyword is "Alpha") and keep the output inside the working directory of the initial file I ran the command on.
The command works such that it requires to you to provide the initial file to perform the command on and then the name of the newly converted file. So like this
command file_to_run_command_on.txt new_file.txt
This is my code
find $PWD -name *.txt* -exec command {} new_file. \;
Right now, it finds all the text files in this directory even in the sub directories and outputs just one file in the directory I run the initial find command from. I'm also unsure how to add the additional search for the keyword in the directory. All advice appreciated!
-exec runs the command in the directory from which you start find.
-execdir runs the command in the matching file's directory.
To only find *.txt* files whose parents contain a specific file, you could use:
find "$PWD" -path "*keyword*/*.txt*" -execdir command {} new_file \;
This will run the command for foo/bar/some-keyword-dir/baz/etc/file.txts but not for foo/bar/baz/file.txts (no keyword in parent directory names) or foo/bar/some-keyword-dir/baz/file.tar (not *.txt*)
I am not familiar with osx terminal command.
I have a java project containing many package.
Some classes have same name in different package.
I need to copy all of the class files into a directory, so I need to add
corresponding package prefix on each files.
For example, I have root/com/example1/test.java and root/com/example2/test.java two classes having the same name in different packages. I need to copy them into root directory and add prefix, making them become example1.test.java and example2.test.java in root directory.
How to do this using terminal command?
This solution is not perfect but it should do what you want (assuming I understood your question correctly):
Create a file doCopy.sh with the following content:
#!/bin/bash
origName=$1
newName=$(echo $origName | sed -e 's|/|.|g')
echo cp $origName $newName
Then make it executable and call it for each of your files:
chmod +x doCopy.sh
find root -type f -exec ./doCopy.sh {} \;
Please verify the commands that will be printed. If you are satisfied you can remove the echo from doCopy.sh and rerun the find to actually copy the files.
I've been working on a script but always with a fixed directory (/opt/mw/script).
I need to change that to be able to execute the script from any directory.
I think I will need to add a "." at the beginning of the line to be able to execute the script?
For example ./mw/script
Is this correct?
Thanks
You already can execute that script from any directory with that absolute file path. It's the relative file paths (that start with ./ or ../) that can only be executed from a specific directory.
You need to add the "." if the script is in the current directory (e.g. ./script), but it is optional if the script is already inside another directory (e.g. mw/script).
Also notice that if your script contains relative references to other files and directories, you may need to use this trick to properly refer to them from any directory.
For instance, consider the following script using absolute paths:
#!/bin/bash
# lists all files in this directory
ls /opt/mw
If it is converted to relative paths as follows:
#!/bin/bash
# lists all files in this directory
ls mw
Then this script will only work if you run it from its own directory (e.g. cd /opt/ && ./script).
But then you can generalize it like this:
#!/bin/bash
SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
# lists all files in this directory
ls $SCRIPT_DIR/mw
Now the script works even when executed from another directory.
I want to copy (and overwrite) files and folders from a directory hierarch, only if they have a common string in name like 'fabrik'.
Example directory: com_fabrik, example file: fabriklist.php
Which terminal command should I use to execute this copy?
Use find
find /your/directory -name="*.php" -exec cp -R {} ../otherfolder \;