Xargs
From charlesreid1
Contents
Overview
xargs is a very handy command line utility that allows you to perform operations on a list. For example, you can take a list of files and tell xargs to run the "rm" command on the list to remove each file on the list. Or you can use xargs to unzip a list of files. Think of it as a quick-and-dirty way to do a bash loop like
for i in `cat list_of_files`; do command $i done
except with the flexibility to do more complex things with either the input or the output of the loop. It has the additional advantage that it performs the command once for each argument in the list.
To understand this as an advantage, see wikipedia:xargs - the example they give is for the "rm" command, which cannot take extremely long lists of files. To circumvent this, xargs will run the "rm" command once for each file in the list.
To see the maximum size of any argument list for a command, execute this:
$ getconf ARG_MAX 262144
Usage
Basic Usage
xargs is almost always called to receive information from a pipe.
One of the most convenient uses of xargs is to grep through files, or to remove lists of files.
For example, to search through C++ code files for the word "turbulence," you could use xargs as follows:
$ find . -name "*.cc" | xargs grep "turbulence" ./Arches.cc: //db->require("turbulence_model", turbModel); ./BoundaryCondition.cc: // --- new turbulence inlet flow generator --- ./BoundaryCondition.cc: turb_db->get("turbulence_intensity",intensity); ./CompDynamicProcedure.cc:// Schedule recomputation of the turbulence sub model ./CompDynamicProcedure.cc:// Schedule recomputation of the turbulence sub model ./CompLocalDynamicProcedure.cc:// Schedule recomputation of the turbulence sub model ./CompLocalDynamicProcedure.cc:// Schedule recomputation of the turbulence sub model ./EnthalpySolver.cc: // if it is set in turbulence model ./IncDynamicProcedure.cc:// Schedule recomputation of the turbulence sub model ./IncDynamicProcedure.cc:// Schedule recomputation of the turbulence sub model ./OdtClosure.cc:// Schedule recomputation of the turbulence sub model ./ReactiveScalarSolver.cc: // if it is set in turbulence model ./ScalarSolver.cc: // if it is set in turbulence model ./ScalarSolver.cc: // we only need to set mixture fraction Pr number in turbulence model ./ScaleSimilarityModel.cc:// Schedule recomputation of the turbulence sub model ./SmagorinskyModel.cc:// Schedule recomputation of the turbulence sub model ./SmagorinskyModel.cc:// Schedule recomputation of the turbulence sub model ./SmagorinskyModel.cc:// Schedule recomputation of the turbulence sub model
Or, to remove a set of files contained in a list contained in a file, you could use:
$ cat list_file | xargs rm
REMEMBER: before running "xargs rm" with ANYTHING, you should run the plain command by itself first, or run "xargs cat", to print the names of the files that will be removed. This prevents you from shooting yourself in the foot:
for i in $EXTREMITIES; do rm $i; done
Creating Files
I mentioned there are lots of creative uses for files. One example would be to create a bunch of files from a list of file names:
$ cat list_of_files | xargs touch
Or, if you want to touch a bunch of files matching certain criteria. An example is if you're on a filesystem that deletes files older than X days, and you want to touch any directory that is X-1 days old, you can feed arguments to find so that it will return directories that are X-1 days old, and then feed that to "xargs touch".
Double-Checking Xargs Commands
The -p (lowercase p) and -t flags can be very useful in making sure that you are executing the commands correctly.
Using the -p flag causes xargs to print out each command that it will execute and ask for confirmation from the user.
Using the -t flag causes xargs to print out each command that it will execute to stderr before it executes the command.
Advanced Usage
Dealing with Newline Characters
One of the problems with combining find with xargs is if you've got spaces or newlines or weird characters in your list of files. In this case, you can use some arguments for find and xargs to prevent you from screwing stuff up:
$ find . -name "*.cc" -print0 | xargs -0 grep "something"
The -print0 argument for find is explained in the man page for find (man find):
-print0 This primary always evaluates to true. It prints the pathname of the current file to standard output, followed by an ASCII NUL character (character code 0).
Likewise, the -0 argument for xargs is explained (in man xargs):
-0 Change xargs to expect NUL (``\0'') characters as separators, instead of spaces and newlines. This is expected to be used in concert with the -print0 function in find(1).
Manipulating the Argument List
Sometimes you don't just want to feed the argument list, one at a time, to a command. You might want to insert the name of the file somewhere as a part of the command - "mv" and "cp" are examples of this. For example, you don't say "cp file" (which is what would happen if you pipe the names of files to "xargs cp"), you say "cp file /destination/dir/".
You can insert the name of the file by using the -I flag. From the xargs manpage (man xargs):
-I replstr Execute utility for each input line, replacing one or more occurrences of replstr in up to replacements (or 5 if no -R flag is specified) arguments to utility with the entire line of input. The resulting arguments, after replacement is done, will not be allowed to grow beyond 255 bytes; this is implemented by concatenating as much of the argument containing replstr as possible, to the constructed arguments to utility, up to 255 bytes. The 255 byte limit does not apply to arguments to utility which do not contain replstr, and furthermore, no replacement will be done on utility itself. Implies -x.
So, an example of this would be:
$ $ find . -name "*.cc" -print0 | xargs -0 -I {} cp {} /temp/.
This would copy all of the *.cc files returned by find into the /temp/ directory. Note that this would destroy the directory structure. If you want to preserve the directory structure, you would probably want to use plain old "cp -R".
-I vs. -J
-I and -J seem at first blush to be redundant - both replace strings, both allow for slightly more complex commands to be executed. However, there is a very big difference:
Using "xargs -J rplstr" will cause xargs to print, all at once, whatever arguments are being piped to it, wherever it finds rplstr.
Using "xargs -I rplstr" will cause xargs to print, one at a time, whatever arguments are being piped to it, wherever it finds rplstr.
This becomes more clear with some examples. Let's say we have a list of file names that we want to create:
$ cat list_of_files file1 file2 file3
We can pipe this list to "xargs touch" to create the files.
$ cat list_of_files | xargs -t touch touch file1 file2 file3
This appends the entirety of stdout to the end of the command. The -J argument will do the exact same thing, except instead of appending the entirety of stdout to the end of the command, it will insert it wherever rplstr shows up.
This example copies all the files that were just touched (file1, file2, file3) into one directory higher:
$ cat list_of_files | xargs -t -J % cp % ../ cp file1 file2 file3 ../
But now let's say we want to rename each file, from "file1" to "new_file1", "file2" to "new_file2", and "file3" to "new_file3":
$ cat list_of_files | xargs -t -J % mv % new_% mv file1 file2 file3 new_% usage: mv [-f | -i | -n] [-v] source target mv [-f | -i | -n] [-v] source ... directory
Oops - that doesn't work as expected. This is because -J is plopping down everything fed to xargs into the % symbol.
Using -I fixes the problem. First, touching files with -I shows that something different is happening:
$ cat list_of_files | xargs -t -I % touch % touch file1 touch file2 touch file3
Each file is being processed, one at a time.
Likewise:
$ cat list_of_files | xargs -t -I % cp % ../ cp file1 ../ cp file2 ../ cp file3 ../
This shows each file is copied, one at a time.
Now when the move command is given, it works:
$ cat list_of_files | xargs -t -I % mv % new_% mv file1 new_file1 mv file2 new_file2 mv file3 new_file3
The -I flag can also handle spaces:
$ cat list_of_files2 file name one file name two file name three $ cat list_of_files2 | xargs -t -I {} touch {} touch file name one touch file name two touch file name three $ ls -1 file name one file name three file name two list_of_files list_of_files2
The -I argument correctly creates three files named "file name one", "file name two", and "file name three", whereas -J would mess this command up and create files named "file", "name", "one", "two", and "three":
$ cat list_of_files2 | xargs -t -J {} touch {} touch file name one file name two file name three $ ls -1 file list_of_files list_of_files2 name one three two
Furthermore, the -I command can handle each argument in chunks of N pieces, by giving xargs the argument -n N:
$ cat list_of_files2 | xargs -t -n1 -I {} touch {} touch file touch name touch one touch file touch name touch two touch file touch name touch three $ cat list_of_files2 | xargs -t -n2 -I {} touch {} touch file name touch one touch file name touch two touch file name touch three
Furthermore, you can use the replacement string fed to -I in double-quotes, whereas it doesn't work exactly right using the replacement string fed to -J:
$ cat list_of_files2 | xargs -I {} echo "Hello from {}" Hello from file name one Hello from file name two Hello from file name three $ cat list_of_files2 | xargs -J {} echo "Hello from {}" Hello from {} file name one file name two file name three
Doing More Than One Thing With Input List
Let's say you want to do two or three things with the list of inputs coming to xargs. In this case, you can pipe xargs commands to more xargs commands.
Example:
$ cat list_of_files /path/to/file name one /path/to/file name two /path/to/file name three
What if we want to touch a file named "file name one", "file name two", and "file name three" in the current directory, and we want to get rid of the path?
The path can be removed using the "basename" utility, and the file can be created using "touch". But the normal/intuitive way these might be chained together doesn't work:
$ cat list_of_files | xargs -t -I {} touch `basename {}` touch /path/to/file name one touch: /path/to/file name one: No such file or directory touch /path/to/file name two touch: /path/to/file name two: No such file or directory touch /path/to/file name three touch: /path/to/file name three: No such file or directory
This doesn't work because the substitution of {} doesn't happen inside the back-ticks.
To solve this problem, xargs can be piped to xargs:
$ cat list_of_files | xargs -t -I {} basename {} | xargs -t -I {} touch {} basename /path/to/file name one touch file name one basename /path/to/file name two touch file name two basename /path/to/file name three touch file name three $ ls -1 file name one file name three file name two list_of_files
Xargs Parallelization
Xargs can be used to perform tasks in parallel. Many modern machines have 2, 4, or more cores, and most of the time these sit idle. Xargs allows a way to use all of these cores, in a way that will keep the system busy, but won't overwhelm the system.
Passing the -P argument (capital P) specifies how many processes xargs should run.
If I am on a supercomputer node, and I want to run post-processing scripts for my data, I want to be able to use all 8 nodes, because some of this post-processing can take a while if it's run in sequence. If I have data in a set of files, and I have a postprocessing script whose first argument is the data file to postprocess, I can do this as follows:
$ ls -1 data_001 data_002 data_003 data_004 data_005 data_006 data_007 data_008 postprocessing_script.sh
(For this example, postprocessing_script.sh will just print out the name of the data file...)
$ ls -1 data* | xargs -t -P8 -I {} ./postprocessing_script.sh {} ./postprocessing_script.sh data_001 ./postprocessing_script.sh data_002 ./postprocessing_script.sh data_003 data_002 data_001 ./postprocessing_script.sh data_004 ./postprocessing_script.sh data_005 ./postprocessing_script.sh data_006 data_003 ./postprocessing_script.sh data_007 data_004 ./postprocessing_script.sh data_008 data_005 data_007 data_006 data_008
Note the use of -I, so that each file is fed individually to the postprocessing script.
Xargs Jujitsu
SVN
I use xargs in pipes to do some handy stuff. For example, if I am in a directory that is part of an SVN repository, I can run the command "svn status" to tell me about files that have been changed, etc.:
$ svn status . M Core/Grid/Patch.h M Core/Grid/Level.cc M Core/Grid/Level.h M Core/Grid/sub.mk ? Core/Grid/AMR_CoarsenRefine.cc ? Core/Grid/LevelP.h ? Core/Grid/AMR_CoarsenRefine.h M Core/Math/Matrix3.cc M Core/Math/Matrix3.h M Core/Parallel/Parallel.cc M Core/Parallel/Parallel.h M Core/Containers/Handle.h M Core/Containers/RunLengthEncoder.h
Those "?"s mean the files have not been added to the repository yet. In this case, there's only 3, so it would be straightforward to copy-and-paste the file names into an "svn add" command to add the files to the repository. But the smart solution is to make the computer work for you!
First, use grep to reduce the list only to files that haven't been added to the repository yet:
$ svn status . | grep "?" ? Core/Grid/AMR_CoarsenRefine.cc ? Core/Grid/LevelP.h ? Core/Grid/AMR_CoarsenRefine.h
Then use Awk to strip the leading "?":
$ svn status . | grep "?" | awk -F" " '{print $2}' Core/Grid/AMR_CoarsenRefine.cc Core/Grid/LevelP.h Core/Grid/AMR_CoarsenRefine.h
And finally, use xargs to add each file, one-at-a-time, to the repository:
$ svn status . | grep "?" | awk -F" " '{print $2}' | xargs svn add A Core/Grid/AMR_CoarsenRefine.cc A Core/Grid/LevelP.h A Core/Grid/AMR_CoarsenRefine.h
Or, if we wanted to delete them (this would be the case if we wanted to "clean out" and revert a directory to the repository version), we could replace "svn add" with "rm":
$ svn status . | grep "?" | awk -F" " '{print $2}' | xargs rm
REMEMBER: before you run the "rm" command on anything, leave off the "xargs" portion, and make sure that you're slicing-and-dicing correctly (doing everything up until the awk command will just print the names of the files on which "rm" will operate).
Moving Files
I have a lot of audio files that all have a bunch of spaces in their names. I want to move them into the same file names, but with all of the spaces turned into underscores. I can create the list of files I want to create by running:
$ ls -1 1-01 Act 1_ Sc. 1 - Enter Three Witc.m4a 1-02 Act 1_ Sc. 2 - Enter Duncan, Ma.m4a 1-03 Act 1_ Sc. 3 - Enter Three Witc.m4a 1-04 Act 1_ Sc. 3 - Enter Macbeth &.m4a 1-05 Act 1_ Sc. 3 - Enter Ross & Ang.m4a 1-06 Act 1_ Sc. 3 - Macbeth_ Do You.m4a 1-07 Act 1_ Sc. 3 - Macbeth_ Two Tru.m4a 1-08 Act 1_ Sc. 4 - Enter Duncan, Le.m4a 1-09 Act 1_ Sc. 5 - Enter Lady Macbe.m4a 1-10 Act 1_ Sc. 5 - Lady Macbeth_ Th.m4a 1-11 Act 1_ Sc. 5 - Enter Macbeth -.m4a 1-12 Act 1_ Sc. 6 - Enter Duncan, Ba.m4a 1-13 Act 1_ Sc. 7 - Enter Macbeth.m4a 1-14 Act 1_ Sc. 7 - Enter Lady Macbe.m4a $ find * -name "*.m4a" -print0 | xargs -0 -I{} echo {} | sed -e 's/ /_/g' 1-01_Act_1__Sc._1_-_Enter_Three_Witc.m4a 1-02_Act_1__Sc._2_-_Enter_Duncan,_Ma.m4a 1-03_Act_1__Sc._3_-_Enter_Three_Witc.m4a 1-04_Act_1__Sc._3_-_Enter_Macbeth_&.m4a 1-05_Act_1__Sc._3_-_Enter_Ross_&_Ang.m4a 1-06_Act_1__Sc._3_-_Macbeth__Do_You.m4a 1-07_Act_1__Sc._3_-_Macbeth__Two_Tru.m4a 1-08_Act_1__Sc._4_-_Enter_Duncan,_Le.m4a 1-09_Act_1__Sc._5_-_Enter_Lady_Macbe.m4a 1-10_Act_1__Sc._5_-_Lady_Macbeth__Th.m4a 1-11_Act_1__Sc._5_-_Enter_Macbeth_-.m4a 1-12_Act_1__Sc._6_-_Enter_Duncan,_Ba.m4a 1-13_Act_1__Sc._7_-_Enter_Macbeth.m4a 1-14_Act_1__Sc._7_-_Enter_Lady_Macbe.m4a
But the tricky part is trying to execute the actual move command. It requires the original list, and the new list, fed to the same command.
This can be done using sed, which can print the original line and a transformed line. Sed can be used to search using the "s" key letter, but can be used to print using the "p" key letter.
First, surround the file name with double-quotes by replacing the :
$ find * -name "*.m4a" | sed -e 's/.*/"&"/' "1-01 Act 1_ Sc. 1 - Enter Three Witc.m4a" "1-02 Act 1_ Sc. 2 - Enter Duncan, Ma.m4a" "1-03 Act 1_ Sc. 3 - Enter Three Witc.m4a" "1-04 Act 1_ Sc. 3 - Enter Macbeth &.m4a" "1-05 Act 1_ Sc. 3 - Enter Ross & Ang.m4a" "1-06 Act 1_ Sc. 3 - Macbeth_ Do You.m4a" "1-07 Act 1_ Sc. 3 - Macbeth_ Two Tru.m4a" "1-08 Act 1_ Sc. 4 - Enter Duncan, Le.m4a" "1-09 Act 1_ Sc. 5 - Enter Lady Macbe.m4a" "1-10 Act 1_ Sc. 5 - Lady Macbeth_ Th.m4a" "1-11 Act 1_ Sc. 5 - Enter Macbeth -.m4a" "1-12 Act 1_ Sc. 6 - Enter Duncan, Ba.m4a" "1-13 Act 1_ Sc. 7 - Enter Macbeth.m4a" "1-14 Act 1_ Sc. 7 - Enter Lady Macbe.m4a"
The sed man page describes what the ampersand does: it substitutes the string matched by the first portion of the search line into the position of the ampersand character.
s/BRE/replacement/flags Substitute the replacement string for instances of the BRE in the pattern space. Any character other than backslash or <newline> can be used instead of a slash to delimit the BRE and the replacement. Within the BRE and the replacement, the BRE delimiter itself can be used as a literal character if it is preceded by a backslash. The replacement string shall be scanned from beginning to end. An ampersand ( '&' ) appearing in the replacement shall be replaced by the string matching the BRE. The special meaning of '&' in this context can be suppressed by preceding it by a backslash. The characters "\n", where n is a digit, shall be replaced by the text matched by the corresponding backreference expression. The special meaning of "\n" where n is a digit in this context, can be suppressed by preceding it by a backslash. For each other backslash ( '\' ) encountered, the following character shall lose its special meaning (if any). The meaning of a '\' immediately followed by any character other than '&', '\', a digit, or the delimiter character used for this command, is unspecified.
Next, the line must be printed twice, and the second instance transformed. The above command will print the transformed line (the filename with double-quotes). Adding the "p" character will print it a second time.
$ find * -name "*.m4a" | sed -e 's/.*/"&"/;p' "1-01 Act 1_ Sc. 1 - Enter Three Witc.m4a" "1-01 Act 1_ Sc. 1 - Enter Three Witc.m4a" "1-02 Act 1_ Sc. 2 - Enter Duncan, Ma.m4a" "1-02 Act 1_ Sc. 2 - Enter Duncan, Ma.m4a" "1-03 Act 1_ Sc. 3 - Enter Three Witc.m4a" "1-03 Act 1_ Sc. 3 - Enter Three Witc.m4a" "1-04 Act 1_ Sc. 3 - Enter Macbeth &.m4a" "1-04 Act 1_ Sc. 3 - Enter Macbeth &.m4a" "1-05 Act 1_ Sc. 3 - Enter Ross & Ang.m4a" "1-05 Act 1_ Sc. 3 - Enter Ross & Ang.m4a" "1-06 Act 1_ Sc. 3 - Macbeth_ Do You.m4a" "1-06 Act 1_ Sc. 3 - Macbeth_ Do You.m4a" "1-07 Act 1_ Sc. 3 - Macbeth_ Two Tru.m4a" "1-07 Act 1_ Sc. 3 - Macbeth_ Two Tru.m4a" "1-08 Act 1_ Sc. 4 - Enter Duncan, Le.m4a" "1-08 Act 1_ Sc. 4 - Enter Duncan, Le.m4a" "1-09 Act 1_ Sc. 5 - Enter Lady Macbe.m4a" "1-09 Act 1_ Sc. 5 - Enter Lady Macbe.m4a" "1-10 Act 1_ Sc. 5 - Lady Macbeth_ Th.m4a" "1-10 Act 1_ Sc. 5 - Lady Macbeth_ Th.m4a" "1-11 Act 1_ Sc. 5 - Enter Macbeth -.m4a" "1-11 Act 1_ Sc. 5 - Enter Macbeth -.m4a" "1-12 Act 1_ Sc. 6 - Enter Duncan, Ba.m4a" "1-12 Act 1_ Sc. 6 - Enter Duncan, Ba.m4a" "1-13 Act 1_ Sc. 7 - Enter Macbeth.m4a" "1-13 Act 1_ Sc. 7 - Enter Macbeth.m4a" "1-14 Act 1_ Sc. 7 - Enter Lady Macbe.m4a" "1-14 Act 1_ Sc. 7 - Enter Lady Macbe.m4a"
And finally, if any further sed commands are given, they will only be performed on the second (printed) instance of the line:
$ find * -name "*.m4a" | sed -e 's/.*/"&"/;p;s/ /_/g' "1-01 Act 1_ Sc. 1 - Enter Three Witc.m4a" "1-01_Act_1__Sc._1_-_Enter_Three_Witc.m4a" "1-02 Act 1_ Sc. 2 - Enter Duncan, Ma.m4a" "1-02_Act_1__Sc._2_-_Enter_Duncan,_Ma.m4a" "1-03 Act 1_ Sc. 3 - Enter Three Witc.m4a" "1-03_Act_1__Sc._3_-_Enter_Three_Witc.m4a" "1-04 Act 1_ Sc. 3 - Enter Macbeth &.m4a" "1-04_Act_1__Sc._3_-_Enter_Macbeth_&.m4a" "1-05 Act 1_ Sc. 3 - Enter Ross & Ang.m4a" "1-05_Act_1__Sc._3_-_Enter_Ross_&_Ang.m4a" "1-06 Act 1_ Sc. 3 - Macbeth_ Do You.m4a" "1-06_Act_1__Sc._3_-_Macbeth__Do_You.m4a" "1-07 Act 1_ Sc. 3 - Macbeth_ Two Tru.m4a" "1-07_Act_1__Sc._3_-_Macbeth__Two_Tru.m4a" "1-08 Act 1_ Sc. 4 - Enter Duncan, Le.m4a" "1-08_Act_1__Sc._4_-_Enter_Duncan,_Le.m4a" "1-09 Act 1_ Sc. 5 - Enter Lady Macbe.m4a" "1-09_Act_1__Sc._5_-_Enter_Lady_Macbe.m4a" "1-10 Act 1_ Sc. 5 - Lady Macbeth_ Th.m4a" "1-10_Act_1__Sc._5_-_Lady_Macbeth__Th.m4a" "1-11 Act 1_ Sc. 5 - Enter Macbeth -.m4a" "1-11_Act_1__Sc._5_-_Enter_Macbeth_-.m4a" "1-12 Act 1_ Sc. 6 - Enter Duncan, Ba.m4a" "1-12_Act_1__Sc._6_-_Enter_Duncan,_Ba.m4a" "1-13 Act 1_ Sc. 7 - Enter Macbeth.m4a" "1-13_Act_1__Sc._7_-_Enter_Macbeth.m4a" "1-14 Act 1_ Sc. 7 - Enter Lady Macbe.m4a" "1-14_Act_1__Sc._7_-_Enter_Lady_Macbe.m4a"
Finally, xargs can be used to move the first filename printed to the second filename printed. Giving the -n2
argument to xargs tells it to feed 2 arguments at a time to the "mv" command:
$ find * -name "*.m4a" | sed -e 's/.*/"&"/;p;s/ /_/g' | xargs -t -n2 mv mv 1-01 Act 1 Sc. 1 - Enter Three Witc.m4a 1-01_Act_1__Sc._1_-_Enter_Three_Witc.m4a mv 1-02 Act 1 Sc. 2 - Enter Duncan, Ma.m4a 1-02_Act_1__Sc._2_-_Enter_Duncan,_Ma.m4a mv 1-03 Act 1 Sc. 3 - Enter Three Witc.m4a 1-03_Act_1__Sc._3_-_Enter_Three_Witc.m4a mv 1-04 Act 1 Sc. 3 - Enter Macbeth &.m4a 1-04_Act_1__Sc._3_-_Enter_Macbeth_&.m4a mv 1-05 Act 1 Sc. 3 - Enter Ross & Ang.m4a 1-05_Act_1__Sc._3_-_Enter_Ross_&_Ang.m4a mv 1-06 Act 1 Sc. 3 - Macbeth Do You.m4a 1-06_Act_1__Sc._3_-_Macbeth__Do_You.m4a mv 1-07 Act 1 Sc. 3 - Macbeth Two Tru.m4a 1-07_Act_1__Sc._3_-_Macbeth__Two_Tru.m4a mv 1-08 Act 1 Sc. 4 - Enter Duncan, Le.m4a 1-08_Act_1__Sc._4_-_Enter_Duncan,_Le.m4a mv 1-09 Act 1 Sc. 5 - Enter Lady Macbe.m4a 1-09_Act_1__Sc._5_-_Enter_Lady_Macbe.m4a mv 1-10 Act 1 Sc. 5 - Lady Macbeth Th.m4a 1-10_Act_1__Sc._5_-_Lady_Macbeth__Th.m4a mv 1-11 Act 1 Sc. 5 - Enter Macbeth -.m4a 1-11_Act_1__Sc._5_-_Enter_Macbeth_-.m4a mv 1-12 Act 1 Sc. 6 - Enter Duncan, Ba.m4a 1-12_Act_1__Sc._6_-_Enter_Duncan,_Ba.m4a mv 1-13 Act 1 Sc. 7 - Enter Macbeth.m4a 1-13_Act_1__Sc._7_-_Enter_Macbeth.m4a mv 1-14 Act 1 Sc. 7 - Enter Lady Macbe.m4a 1-14_Act_1__Sc._7_-_Enter_Lady_Macbe.m4a
Done.
If there were no spaces, the first section of the sed command would not be needed, and (if one wanted to perform the sed transform s/A/B/g
(meaning, replace all occurrences, on the line/in the filename, of A with B), the command would look like this:
$ find * -name "*.m4a" | sed -e 'p;s/A/B/g' | xargs -t -n2 mv
You can do some pretty nifty stuff with pipes, and if you know a little bit of sed jujitsu.
Thanks to [1] for the handy tip.
References
- Xargs man page: http://unixhelp.ed.ac.uk/CGI/man-cgi?xargs
- Wikipedia article on xargs: http://en.wikipedia.org/wiki/Xargs
- Xargs to do parallel processing: http://blog.labrat.info/20100429/using-xargs-to-do-parallel-processing/
- Controlling and using command line arguments using xargs: http://www.cyberciti.biz/faq/linux-unix-bsd-xargs-construct-argument-lists-utility/
- Xargs and find: http://www.linuxplanet.com/linuxplanet/tutorials/6522/1/
GNU/Linux/Unix the concrete that makes the foundations of the internet.
Compiling Software · Upgrading Software Category:Build Tools · Make · Cmake · Gdb Bash Bash · Bash/Quick (Quick Reference) · Bash Math Text Editors Text Manipulation Command Line Utilities Aptitude · Diff · Make · Patch · Subversion · Xargs Security SSH (Secure Shell) · Gpg (Gnu Privacy Guard) · Category:Security Networking Linux/SSH · Linux/Networking · Linux/File Server Web Servers
|