- How to go to each directory and execute a command?
- 12 Answers 12
- How do I run a program with a different working directory from current, from Linux shell?
- 11 Answers 11
- Execute a specific command in a given directory without cd’ing to it?
- 7 Answers 7
- Execute a command from another directory in bash
- 8 Answers 8
- Execute command on all files in a directory
- 10 Answers 10
How to go to each directory and execute a command?
How do I write a bash script that goes through each directory inside a parent_directory and executes a command in each directory.
The directory structure is as follows:
parent_directory (name could be anything — doesnt follow a pattern)
- 001 (directory names follow this pattern)
- 0001.txt (filenames follow this pattern)
- 0002.txt
- 0003.txt
- 002
- 0001.txt
- 0002.txt
- 0003.txt
- 0004.txt
- 003
- 0001.txt
the number of directories is unknown.
12 Answers 12
This answer posted by Todd helped me.
The \( ! -name . \) avoids executing the command in current directory.
You can do the following, when your current directory is parent_directory :
The ( and ) create a subshell, so the current directory isn’t changed in the main script.
If you’re using GNU find , you can try -execdir parameter, e.g.:
Note: You can use $ <0#./>instead of $0 to fix ./ in the front.
or more practical example:
If you want to include the current directory, it’s even simpler by using -exec :
Or similar example suggested by @gniourf_gniourf:
The above examples support directories with spaces in their name.
Or by assigning into bash array:
Change . to your specific folder name. If you don’t need to run recursively, you can use: dirs=(*) instead. The above example doesn’t support directories with spaces in the name.
So as @gniourf_gniourf suggested, the only proper way to put the output of find in an array without using an explicit loop will be available in Bash 4.4 with:
Or not a recommended way (which involves parsing of ls ):
The above example would ignore the current dir (as requested by OP), but it’ll break on names with the spaces.
Источник
How do I run a program with a different working directory from current, from Linux shell?
Using a Linux shell, how do I start a program with a different working directory from the current working directory?
For example, I have a binary file helloworld that creates the file hello-world.txt in the current directory.
This file is inside of directory /a .
Currently, I am in the directory /b . I want to start my program running ../a/helloworld and get the hello-world.txt somewhere in a third directory /c .
11 Answers 11
Call the program like this:
The parentheses cause a sub-shell to be spawned. This sub-shell then changes its working directory to /c , then executes helloworld from /a . After the program exits, the sub-shell terminates, returning you to your prompt of the parent shell, in the directory you started from.
Error handling: To avoid running the program without having changed the directory, e.g. when having misspelled /c , make the execution of helloworld conditional:
Reducing memory usage: To avoid having the subshell waste memory while hello world executes, call helloworld via exec:
[Thanks to Josh and Juliano for giving tips on improving this answer!]
Similar to David Schmitt’s answer, plus Josh’s suggestion, but doesn’t leave a shell process running:
This way is more similar to how you usually run commands on the shell. To see the practical difference, you have to run ps ef from another shell with each solution.
An option which doesn’t require a subshell and is built in to bash
Источник
Execute a specific command in a given directory without cd’ing to it?
Is there a way to execute a command in a different directory without having to cd to it? I know that I could simply cd in and cd out, but I’m just interested in the possibilities of forgoing the extra steps 🙂
7 Answers 7
I don’t know if this counts, but you can make a subshell:
The directory is only changed for that subshell, so you avoid the work of needing to cd — afterwards.
/Desktop) . That way, if the directory doesn’t exist, no further commands are executed.
Not to undermine the value of answers given by other people, but I believe what you want is this:
Note the parens to invoke cd in a sub-shell.
Some programs have options with which you can tell them to chdir(2) themselves (e.g. GNU tar’s -C / —directory ).
Outside of such programs though, something will have to chdir. You could write and use some sort of compiled “binary” program instead of having the shell do it, but it probably would not yield much benefit.
In a comment in another answer, you gave an example:
Since the *.log pattern is expanded by the shell itself (not cp), something will have to chdir to the directory before having a shell evaluate your command.
If you are just interesting in avoiding having to “cd back”, then you can use a subshell to isolate the effect of the cd from your working shell instance.
You can package this up in a shell function. (I dropped the -d option from your example usage since there is little point to this command if the directory is actually optional.)
Источник
Execute a command from another directory in bash
Say that I’m doing this:
Is there a way to do this with a single command, or perhaps two, rather than having to move in and out of a directory in order to run a command there?
(Not looking for a git-specific solution; that’s just an example.)
8 Answers 8
This is often the best way:
It’s pretty short and easy to type. It does start a sub-shell, so you can’t modify your environment from that, but that doesn’t seem to be an issue here.
I was looking for a way to execute the git command from a path, and make changes to the repository in a different path. So I ended up in this question here.
But for my specific needs neither the accepted answer nor any of the other ones helped.
I needed to run git commands using sudo -u USER /usr/bin/git (another user running it). And as you may know, sudo doesn’t allow me to run the cd command, so I can’t be in the repository directory.
So, I went to git’s man page. And among the options, I saw the —git-dir=
Set the path to the repository. This can also be controlled by setting the GIT_DIR environment variable. It can be an absolute path or relative path to current working directory.
So, if it help someone, you can still use git from a path and make changes to a repository «far from you». Just use:
or, to run it as another user, do something like:
If the $GIT_DIR environment variable is set then it specifies a path to use instead of ./.git for the base of the repository.
So, if you want to init the repository under the usual .git folder, you will need to specify it together with the —git-dir option. e.g.:
After initializing the repository on /path/to/repo/.git , all further commands should have the option —work-tree=
, as described on git’s man page:
Set the path to the working tree. It can be an absolute path or a path relative to the current working directory. This can also be controlled by setting the GIT_WORK_TREE environment variable and the core.worktree configuration variable (see core.worktree in git-config(1) for a more detailed discussion).
So, the right command to run git as another user, and initialize a new repository is:
Источник
Execute command on all files in a directory
Could somebody please provide the code to do the following: Assume there is a directory of files, all of which need to be run through a program. The program outputs the results to standard out. I need a script that will go into a directory, execute the command on each file, and concat the output into one big output file.
For instance, to run the command on 1 file:
10 Answers 10
The following bash code will pass $file to command where $file will represent every file in /dir
- -maxdepth 1 argument prevents find from recursively descending into any subdirectories. (If you want such nested directories to get processed, you can omit this.)
- -type -f specifies that only plain files will be processed.
- -exec cmd option <> tells it to run cmd with the specified option for each file found, with the filename substituted for <>
- \; denotes the end of the command.
- Finally, the output from all the individual cmd executions is redirected to results.out
However, if you care about the order in which the files are processed, you might be better off writing a loop. I think find processes the files in inode order (though I could be wrong about that), which may not be what you want.
I’m doing this on my raspberry pi from the command line by running:
The accepted/high-voted answers are great, but they are lacking a few nitty-gritty details. This post covers the cases on how to better handle when the shell path-name expansion (glob) fails, when filenames contain embedded newlines/dash symbols and moving the command output re-direction out of the for-loop when writing the results to a file.
When running the shell glob expansion using * there is a possibility for the expansion to fail if there are no files present in the directory and an un-expanded glob string will be passed to the command to be run, which could have undesirable results. The bash shell provides an extended shell option for this using nullglob . So the loop basically becomes as follows inside the directory containing your files
This lets you safely exit the for loop when the expression ./* doesn’t return any files (if the directory is empty)
or in a POSIX compliant way ( nullglob is bash specific)
This lets you go inside the loop when the expression fails for once and the condition [ -f «$file» ] check if the un-expanded string ./* is a valid filename in that directory, which wouldn’t be. So on this condition failure, using continue we resume back to the for loop which won’t run subsequently.
Also note the usage of — just before passing the file name argument. This is needed because as noted previously, the shell filenames can contain dashes anywhere in the filename. Some of the shell commands interpret that and treat them as a command option when the name are not quoted properly and executes the command thinking if the flag is provided.
The — signals the end of command line options in that case which means, the command shouldn’t parse any strings beyond this point as command flags but only as filenames.
Double-quoting the filenames properly solves the cases when the names contain glob characters or white-spaces. But *nix filenames can also contain newlines in them. So we de-limit filenames with the only character that cannot be part of a valid filename — the null byte ( \0 ). Since bash internally uses C style strings in which the null bytes are used to indicate the end of string, it is the right candidate for this.
So using the printf option of shell to delimit files with this NULL byte using the -d option of read command, we can do below
The nullglob and the printf are wrapped around (..) which means they are basically run in a sub-shell (child shell), because to avoid the nullglob option to reflect on the parent shell, once the command exits. The -d » option of read command is not POSIX compliant, so needs a bash shell for this to be done. Using find command this can be done as
For find implementations that don’t support -print0 (other than the GNU and the FreeBSD implementations), this can be emulated using printf
Another important fix is to move the re-direction out of the for-loop to reduce a high number of file I/O. When used inside the loop, the shell has to execute system-calls twice for each iteration of the for-loop, once for opening and once for closing the file descriptor associated with the file. This will become a bottle-neck on your performance for running large iterations. Recommended suggestion would be to move it outside the loop.
Extending the above code with this fixes, you could do
which will basically put the contents of your command for each iteration of your file input to stdout and when the loop ends, open the target file once for writing the contents of the stdout and saving it. The equivalent find version of the same would be
Источник