Accsesing linux directories every time using git [duplicate] - linux

My book states:
Every program that runs on your computer has a current working directory, or cwd. Any filenames or paths that do not begin with the root folder are assumed to be under the current working directory
As I am on OSX, my root folder is /. When I type in os.getcwd() in my Python shell, I get /Users/apple/Documents. Why am I getting the Documents folder in my cwd? Is it saying that Python is using Documents folder? Isn't there any path heading to Python that begins with / (the root folder)? Also, does every program have a different cwd?

Every process has a current directory. When a process starts, it simply inherits the current directory from its parent process; and it's not, for example, set to the directory which contains the program you are running.
For a more detailed explanation, read on.
When disks became large enough that you did not want all your files in the same place, operating system vendors came up with a way to structure files in directories. So instead of saving everything in the same directory (or "folder" as beginners are now taught to call it) you could create new collections and other new collections inside of those (except in some early implementations directories could not contain other directories!)
Fundamentally, a directory is just a peculiar type of file, whose contents is a collection of other files, which can also include other directories.
On a primitive operating system, that was where the story ended. If you wanted to print a file called term_paper.txt which was in the directory spring_semester which in turn was in the directory 2021 which was in the directory studies in the directory mine, you would have to say
print mine/studies/2021/spring_semester/term_paper.txt
(except the command was probably something more arcane than print, and the directory separator might have been something crazy like square brackets and colons, or something;
lpr [mine:studies:2021:spring_semester]term_paper.txt
but this is unimportant for this exposition) and if you wanted to copy the file, you would have to spell out the whole enchilada twice:
copy mine/studies/2021/spring_semester/term_paper.txt mine/studies/2021/spring_semester/term_paper.backup
Then came the concept of a current working directory. What if you could say "from now on, until I say otherwise, all the files I am talking about will be in this particular directory". Thus was the cd command born (except on old systems like VMS it was called something clunkier, like SET DEFAULT).
cd mine/studies/2021/spring_semester
print term_paper.txt
copy term_paper.txt term_paper.backup
That's really all there is to it. When you cd (or, in Python, os.chdir()), you change your current working directory. It stays until you log out (or otherwise exit this process), or until you cd to a different working directory, or switch to a different process or window where you are running a separate command which has its own current working directory. Just like you can have your file browser (Explorer or Finder or Nautilus or whatever it's called) open with multiple windows in different directories, you can have multiple terminals open, and each one runs a shell which has its own independent current working directory.
So when you type pwd into a terminal (or cwd or whatever the command is called in your command language) the result will pretty much depend on what you happened to do in that window or process before, and probably depends on how you created that window or process. On many Unix-like systems, when you create a new terminal window with an associated shell process, it is originally opened in your home directory (/home/you on many Unix systems, /Users/you on a Mac, something more or less like C:\Users\you on recent Windows) though probably your terminal can be configured to open somewhere else (commonly Desktop or Documents inside your home directory on some ostensibly "modern" and "friendly" systems).
Many beginners have a vague and incomplete mental model of what happens when you run a program. Many will incessantly cd into whichever directory contains their script or program, and be genuinely scared and confused when you tell them that you don't have to. If frobozz is in /home/you/bin then you don't have to
cd /home/you/bin
./frobozz
because you can simply run it directly with
/home/you/bin/frobozz
and similarly if ls is in /bin you most definitely don't
cd /bin
./ls
just to get a directory listing.
Furthermore, like the ls (or on Windows, dir) example should readily convince you, any program you run will look in your current directory for files. Not the directory the program or script was saved in. Because if that were the case, ls could only produce a listing of the directory it's in (/bin) -- there is nothing special about the directory listing program, or the copy program, or the word processor program; they all, by design, look in the current working directory (though again, some GUI programs will start with e.g. your Documents directory as their current working directory, by design, at least if you don't tell them otherwise).
Many beginners write scripts which demand that the input and output files are in a particular directory inside a particular user's home directory, but this is just poor design; a well-written program will simply look in the current working directory for its input files unless instructed otherwise, and write output to the current directory (or perhaps create a new directory in the current directory for its output if it consists of multiple files).
Python, then, is no different from any other programs. If your current working directory is /Users/you/Documents when you run python then that directory is what os.getcwd() inside your Python script or interpreter will produce (unless you separately os.chdir() to a different directory during runtime; but again, this is probably unnecessary, and often a sign that a script was written by a beginner). And if your Python script accepts a file name parameter, it probably should simply get the operating system to open whatever the user passed in, which means relative file names are relative to the invoking user's current working directory.
python /home/you/bin/script.py file.txt
should simply open(sys.argv[1]) and fail with an error if file.txt does not exist in the current directory. Let's say that again; it doesn't look in /home/you/bin for file.txt -- unless of course that is also the current working directory of you, the invoking user, in which case of course you could simply write
python script.py file.txt
On a related note, many beginners needlessly try something like
with open(os.path.join(os.getcwd(), "input.txt")) as data:
...
which needlessly calls os.getcwd(). Why is it needless? If you have been following along, you know the answer already: the operating system will look for relative file names (like here, input.txt) in the current working directory anyway. So all you need is
with open("input.txt") as data:
...
One final remark. On Unix-like systems, all files are ultimately inside the root directory / which contains a number of other directories (and usually regular users are not allowed to write anything there, and system administrators with the privilege to do it typically don't want to). Every relative file name can be turned into an absolute file name by tracing the path from the root directory to the current directory. So if the file we want to access is in /home/you/Documents/file.txt it means that home is in the root directory, and contains you, which contains Documents, which contains file.txt. If your current working directory were /home you could refer to the same file by the relative path you/Documents/file.txt; and if your current directory was /home/you, the relative path to it would be Documents/file.txt (and if your current directory was /home/you/Music you could say ../Documents/file.txt but let's not take this example any further now).
Windows has a slightly different arrangement, with a number of drives with single-letter identifiers, each with its own root directory; so the root of the C: drive is C:\ and the root of the D: drive is D:\ etc. (and the directory separator is a backslash instead of a slash, although you can use a slash instead pretty much everywhere, which is often a good idea for preserving your sanity).

Your python interpreter location is based off of how you launched it, as well as subsequent actions taken after launching it like use of the os module to navigate your file system. Merely starting the interpreter will place you in the directory of your python installation (not the same on different operating systems). On the other hand, if you start by editing or running a file within a specific directory, your location will be the folder of the file you were editing. If you need to run the interpreter in a certain directory and you are using idle for example, it is easiest to start by creating a python file there one way or another and when you edit it you can start a shell with Run > Python Shell which will already be in that directory. If you are using the command line interpreter, navigate to the folder where you want to run your interpreter before running the python/python3/py command. If you need to navigate manually, you can of course use the following which has already been mentioned:
import os
os.chdir('full_path_to_your_directory')

This has nothing to do with osx in particular, it's more of a concept shared by all unix-based systems, and I believe Windows as well. os.getcwd() is the equivalent of the bash pwd command - it simply returns the full path of the current location in which you are in. In other words:
alex#suse:~> cd /
alex#suse:/> python
Python 2.7.12 (default, Jul 01 2016, 15:34:22) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.getcwd()
'/'
It depends from where you started the python shell/script.

Python is usually (except if you are working with virtual environments) accessible from any of your directory. You can check the variables in your path and Python should be available. So the directory you get when you ask Python is the one in which you started Python. Change directory in your shell before starting Python and you will see you will it.

os.getcwd() has nothing to do with OSX in particular. It simply returns the directory/location of the source-file. If my source-file is on my desktop it would return C:\Users\Dave\Desktop\ or let say the source-file is saved on an external storage device it could return something like G:\Programs\. It is the same for both unix-based and Windows systems.

Related

Execute a bash script without typing ./ [duplicate]

I feel like I'm missing something very basic so apologies if this question is obtuse. I've been struggling with this problem for as long as I've been using the bash shell.
Say I have a structure like this:
├──bin
├──command (executable)
This will execute:
$ bin/command
then I symlink bin/command to the project root
$ ln -s bin/command c
like so
├──c (symlink to bin/command)
├──bin
├──command (executable)
I can't do the following (errors with -bash: c: command not found)
$ c
I must do?
$ ./c
What's going on here? — is it possible to execute a command from the current directory without preceding it with ./ and also without using a system wide alias? It would be very convenient for distributed executables and utility scripts to give them one letter folder specific shortcuts on a per project basis.
It's not a matter of bash not allowing execution from the current directory, but rather, you haven't added the current directory to your list of directories to execute from.
export PATH=".:$PATH"
$ c
$
This can be a security risk, however, because if the directory contains files which you don't trust or know where they came from, a file existing in the currently directory could be confused with a system command.
For example, say the current directory is called "foo" and your colleague asks you to go into "foo" and set the permissions of "bar" to 755. As root, you run "chmod foo 755"
You assume chmod really is chmod, but if there is a file named chmod in the current directory and your colleague put it there, chmod is really a program he wrote and you are running it as root. Perhaps "chmod" resets the root password on the box or something else dangerous.
Therefore, the standard is to limit command executions which don't specify a directory to a set of explicitly trusted directories.
Beware that the accepted answer introduces a serious vulnerability!
You might add the current directory to your PATH but not at the beginning of it. That would be a very risky setting.
There are still possible vulnerabilities when the current directory is at the end but far less so this is what I would suggest:
PATH="$PATH":.
Here, the current directory is only searched after every directory already present in the PATH is explored so the risk to have an existing command overloaded by an hostile one is no more present. There is still a risk for an uninstalled command or a typo to be exploited, but it is much lower. Just make sure the dot is always at the end of the PATH when you add new directories in it.
You could add . to your PATH. (See kamituel's answer for details)
Also there is ~/.local/bin for user specific binaries on many distros.
What you can do is add the current dir (.) to the $PATH:
export PATH=.:$PATH
But this can pose a security issue, so be aware of that. See this ServerFault answer on why it's not so good idea, especially for the root account.

What is the filepath difference between window and linux in python3?

Right now I am creating a text file, and then writing som text to it with the command (in python 3):
userFile = open("users\\"+userName+".txt","w")
This creates the file in the folder named users, but when I run the program on a linux system, it instead creates, in the root folder, a file named users\userName.txt
How is the path definition different for python 3 in linux?
Windows has drives (C:, D:, X: etc) and backslashes or double backslashes, e.g.
C:\Users\JohnSmith is the same as C:\\Users\\JohnSmith
On Linux, there are no drives (per se) and forward slashes, e.g.
/home/name
The best way to get a feel for paths is by using os. Try typing this into your python terminal print(os.path.abspath('.'))
It's not different in python 3 in linux it's different in linux. Generally speaking *nix file paths use / as a directory separator, where as windows uses \ (for what ever reason).
In python 3 you can use the pathlib.Path to abstract your code from the OS. So you can do something like
open(Path(f"~/{username}.txt"), "w")
The tilde ~ refers to a user's home directory. Python will figure out which file system the code is running on and do the right thing to map directory separators. You could also do
open(Path(f"/users/{username}.txt"), "w")
to address a specific user directory, the / refers to the root of the file system and should work on Linux and Windows (although I haven't tested that).
https://docs.python.org/3/library/pathlib.html?highlight=pathlib%20path#module-pathlib

Odd behaviour of pwd with symlinks in terminal tabs

If I create a symlink through
ln -s /path/to/linked/dir current/path/link_name
and change the directory to current/path/link_name via
cd link_name
then I can check where I am using pwd-command. The output will be
current/path/link_name
But if I use some terminal emulator, such as terminator, konsole or others, I can split the tab or create a new tab in the same directory. The output of the pwd-command in the newly created tab will be
/path/to/linked/dir
In many cases, this is not convenient. Does anybody know how to change this behaviour in some terminal emulator(s)?
P.S. I also noticed that the output of ls typed from /current/path/link_name is the same as the output of ls typed from /path/to/linked/dir.
You can't. The reason is that you lose the information on how did you get there after the system call has executed. Some terminal emulators and mainly the bash(1) shell try to remember this, and implement pwd as an internal command, to cope with this scenarios. But in general if you try
/bin/pwd
You'll discover that all the information about how did you get to that final directory was lost in the course of time.
Ask yourself how can the /bin/pwd work and how can it determine the directory you are on, and you'll answer yourself the question:
The system maintains a current directory (the pwd command inherits this from its parent shell) in the system data for each process, but to save resources, it only stores the inode number of the directory that is actually your current directory (not actually, it maintains a reference to the in-core inode structure). It doesn't store the path you used to locate it, and it stores that info only to be able to get a starting point when you ask for a relative path when opening a file. The problem is the same as determining which directory a multiple linked file belongs to... no parent directory is stored for a file, as it can be in multiple directories linking to it all at the same time... this is also true for directories, but they have an .. entry inside themselves that links to their parents (their true parents, as one directory is now allowed to belong to different directories by means on normal links, this is forbidden by system, and ensured by the mkdir(2) system call) The pwd(1) commands uses precisely these links to find the parent directory (and then find the current dir in the parent directory, by searching for the inode number of the current directory on it), until this algorithm leads to the same inode (the root directory has this special characteristic, its .. entry points again to itself) so it stops going up. pwd can only work because it is following directories, and never files.
Terminator 1.90 does what you want. In an example session:
$ cd -- "$(mktemp --directory)"
$ mkdir a
$ ln -s a b
$ cd b
Press Ctrl-Shift-e (or o, or t). At this point I'm still in b.

Tcl script cannot open file on Linux (Works on Windows)

I have a Tcl script that works on Windows. When I run it and pass in file names when prompted, usually with a relative directory path. On Windows the script will take absolute OR relative directory paths ... it works, no problems at all.
On Linux it will NOT work in the same way. It will only work if I spell out the full file path, e.g. /home/gxuser/input/test.txt ... It will NOT take relative directory paths like ./input/test.txt
By "work" I mean it should OPEN the file ... It is there and the permissions are fine.
On Linux the program fails with the following error:
couldn't open "./input/test.txt": no such file or directory
while executing
"open $upload r"
The offending line in the code is:
set infile [open $upload r]
What am I doing wrong? I presume, I have overlooked some nuance of the Tcl language, and assumed it should recognize relative paths.
Relevant information:
% puts $tcl_version
8.4
% info patchlevel
8.4.19
% uname -a
Linux gxengine 2.6.32-60-generic #122-Ubuntu SMP
It is possible that a function you call is changing the current working directory. There is no way to tell which one that could be without inspecting the code, but you can check if this is the case by displaying [pwd] before calling open.
Another way things could go wrong is by the script being started in different ways from Unix and Windows - e.g. by shortcut on Windows and from the command line off the PATH on Unix.
Where you have filenames passed in by the user and you can't be sure that code you call won't cd under your feet, you're advised to process the filenames into absolute filenames as soon as possible in your script, possibly even before any package require or source calls.
This is actually easy to do.
set absoluteFilename [file normalize $userProvidedFilename]
As long as this is done before the first cd (or chdir()/SetCurrentDirectory() at the C/C++ level) future changes of directory will not break the path. The script must be prepared to work with absolute filenames, but that's easily done.
You can turn a relative path into an absolute path with respect to any arbitrary directory with file join:
set filename [file join [file normalize $arbitraryLocation] $relativeFilename]
(The file join is smarter than just inserting a directory separator.)

Setting bash command-line variable to start my application

I'm pretty new to programming for Linux environments, so I don't exactly know what to search for in order to answer this question for myself. I need to understand how applications set the shell to accept a certain command to start them. For example, you can start Firefox from the command line by executing the command: firefox.
I don't know where this is defined. Makefile? Configure script? In the source code itself?
Any resources / reading on Linux programming tidbits like these would be greatly appreciated!
Thank you.
Firefox is launched by the command "firefox" because there is an executable file in one of the folders in the $PATH environment variable called "firefox".
Are you talking about the PATH variable? It seems like you are.
In linux, you should be able to type: "echo $PATH" (without quotes) and get a ":"-separated list of locations where programs are located (like firefox).
If you need to add something to your path, you should be able to do:
export PATH=$PATH:/another/directory
In your shell (which is most likely bash)
You can also type:
which firefox
To display the location of the firefox executable.
Typically the shell is going to have an environment variable called $PATH set. This is just an ordered list of all the directories to look when somebody types in a command. As soon as it finds an executable file (by which I mean a file for which you have execute permissions, not a file ending in .exe) with the same name as whatever was typed, it will run that file. Common directories in $PATH might be /bin, /usr/local/bin, ~/bin, etc.
So, when you type 'firefox', the shell looks through all the directories in $PATH until it finds /usr/local/bin/firefox, which it then runs. To make your own programs run the same way, you'll either need to put them (or a symbolic link to them) in a directory that is likely to be in every user's path (/usr/local/bin/ is a good choice), or you'll need to get your users to add your program's directory to their $PATH.
For a more complete description, see the Wikipedia article about the $PATH variable.
As an alternative to the modification of $PATH mentioned earlier, you could also copy or link your executable in one of the directories already in your $PATH. more specifically, /usr/local/bin/ is available on most UNIX system for pretty much this purpose (installing software outside the default package management of the operating system).
It has to be in the path as everyone else mentioned, but you might also need to make it executable with something like this:
chmod +x /path/to/file
And if it's a script there's usually a shebang at the top that tells the os what to use to execute it:
#! /usr/bin/python
Often, large packages are installed in /opt with a wrapper script or link somewhere in the PATH. For example, on my system, Google Picasa is installed in /opt/google/picasa and there is a symlink at /usr/bin/picasa to /opt/google/picasa/3.0/picasa
Firefox is at /usr/bin/firefox on my system and that's a symlink to /usr/bin/firefox-3.0 which is itself a symlink to /usr/lib/firefox-3.0.11/firefox.sh - That shell file fumbles around until it finally runs /usr/lib/firefox-3.0.11/firefox (unless it finds a reason to do something else). That, finally, is a binary executable. So /usr/lib is where firefox is installed, for me.
You can use this command to find out where a program is:
type -a firefox
Then, you can find out what kind of file it is using this:
file /usr/bin/firefox
Also see the Filesystem Heirarchy Standard for more information about recommended locations for files and programs.

Resources