"xargs -a file" to copy files to a folder - linux

I am tring to use xargs -a to read the contents of a file that has a list of filenames in it.
My directory working in looks like:
backups
file1.bak
file2.bak
file3.bak
bakfiles.txt
File name with filenames in it: bakfiles.txt
bakfiles.txt contents:
file1.bak
file2.bak
file3.bak
So essentially I'm trying to copy file1.bak,file2.bak,file3.bak into the folder backups. But using the contents of bakfiles.txt to do so.
I tried:
xargs -a bakfiles.txt | cp {} backups
But I get the error:
cp: cannot stat `{}': No such file or directory
I should mention i also tried:
xargs -a bakfiles.txt cp {} backups
And get the error:
cp: target `file3.bak' is not a directory

This works for me on Windows 7 using mks toolkit version of 'xargs'
cat bakfiles.txt | xargs -I '{}' cp '{}' backups/'{}'

From the following link i figured it out:
https://superuser.com/questions/180251/copy-list-of-files
Heres the command:
xargs -a bakfiles.txt cp -t backups

Related

xargs cp how to use asterix?

I'm trying to copy files by mask with preserving folder structure(using --parents), I can't use cp -r --parents or rsync directly because of argument list too long error.
ls folder1/folder2/ | head | xargs -I {} cp -r --parents folder1/folder2/{}/neutral* neutral_data/
but seems asterix symbols don't work here as expected, instead I get few errors like:
cp: cannot stat 'folder1/folder2/folder3/neutral*': No such file or directory
What is the proper way of using asterix symbol in this context or maybe any other method to solve this problem?
Update:
Based on this answer https://unix.stackexchange.com/a/5247/221416 I tried
ls folder1/folder2/ | head | xargs -I {} sh -c cp -r --parents folder1/folder2/{}/neutral* neutral_data/
but it gives error:
cp: missing file operand
Here is a solution:
ls folder1/folder2/ | xargs -I {} bash -c "cp -r --parents folder1/folder2/{}/neutral* neutral_data/"

Recursively delete all binary files in folder

I want to recursively delete all binary files in a folder under linux using the command-line or a bash script. I found
grep -r -m 1 "^" path/to/folder | grep "^Binary file"
to list all binary files in path/to/folder at How to list all binary file extensions within a directory tree?. I would now like to delete all these files.
I could do
grep -r -m 1 "^" path/to/folder | grep "^Binary file" | xargs rm
but that is rather fishy as it also tries to delete the files 'Binary', 'file', and 'matches' as in
rm: cannot remove ‘Binary’: No such file or directory
rm: cannot remove ‘file’: No such file or directory
rm: cannot remove ‘matches’: No such file or directory
The question is thus how do I delete those files correctly ?
This command will return all binary executable files recursively within a directory, run this first to ensure proper output.
find . -type f -executable -exec sh -c "file -i '{}' | grep -q 'x-executable; charset=binary'" \; -print
If that works you can pass the output to xargs to delete these files.
find . -type f -executable -exec sh -c "file -i '{}' | grep -q 'x-executable; charset=binary'" \; -print | xargs rm -f
Hope this helped, have an awesome day! :)
I coded a tool, called blobs, that lists runable binaries.
Its readme mentions how to pipe to any other command.
This should do the job, if you are deleting a lot of binrary files in a folder.
find . -type f -executable | xargs rm

How to pipe output from grep to cp?

I have a working grep command that selects files meeting a certain condition. How can I take the selected files from the grep command and pipe it into a cp command?
The following attempts have failed on the cp end:
grep -r "TWL" --exclude=*.csv* | cp ~/data/lidar/tmp-ajp2/
cp: missing destination file operand after
‘/home/ubuntu/data/lidar/tmp-ajp2/’ Try 'cp --help' for more
information.
cp `grep -r "TWL" --exclude=*.csv*` ~/data/lidar/tmp-ajp2/
cp: invalid option -- '7'
grep -l -r "TWL" --exclude=*.csv* | xargs cp -t ~/data/lidar/tmp-ajp2/
Explanation:
grep -l option to output file names only
xargs to convert file list from the standard input to command line arguments
cp -t option to specify target directory (and avoid using placeholders)
you need xargs with the placeholder option:
grep -r "TWL" --exclude=*.csv* | xargs -I '{}' cp '{}' ~/data/lidar/tmp-ajp2/
normally if you use xargs, it will put the output after the command, with the placeholder ('{}' in this case), you can choose the location where it is inserted, even multiple times.
This worked for me when searching for files with a specific date:
ls | grep '2018-08-22' | xargs -I '{}' cp '{}' ~/data/lidar/tmp-ajp2/
To copy files to grep found directories, use -printf to output directories and -i to place the command argument from xarg (after pipe)
find ./ -name 'filename.*' -print '%h\n' | xargs -i cp copyFile.txt {}
this copies copyFile.txt to all directories (in ./) containing "filename"
grep -rl '/directory/' -e 'pattern' | xargs cp -t /directory

copy entire directory excluding a file

As we know, cp -r source_dir intended_new_directory creates a copy of source directory with a new name. Now I want to do the same but want to exclude a particular file. I have found some related answers here, using tar and rsync, but in those solutions I need to create the destination directory first (using mkdir).
I honestly searched a lot, but didn't find exactly what I want.
So far the best I got is this:
tar -c --exclude=\*.dll --exclude=\*.exe sourceDir | tar -x -C destDir
(from http://www.linuxquestions.org/questions/programming-9/how-to-copy-an-entire-directory-structure-except-certain-files-385321/)
If you have binutils, you could use find to filter next cpio to copy (and create directories) :
find <sourceDir> \( ! -name *.dll \) -a \( ! -name *.exe \) | cpio -dumpv <destDir>
Try this by excluding the file using 'grep -v' ->
cp `ls | grep -v <exclude-file>` <dest-dir>
If the directory is not very large I used to write something like this:
src=path/to/source/directory
dst=path/to/destination/directory
find $src -type f | while read f ; do mkdir -p "$dst/`dirname $f`"; cp "$f" "$dst/$f" ; done
Here we list all regular files in $src, iterate over this list and for each file make a directory in $dst if it does not exist yet (-p option of mkdir), then copy the file to that directory.
The above command will copy all the files. Finally, just use
find $src -type f | grep -v whatever | while ...... # same as above
to filter out the files you don't need (e.g. \.bak$, \.orig$, or whatever files you don't want to copy).
Move all exclude file into home or other directory,copy the directory containing all remaining files to the destination folder then restore all exclude files.
#cd mydirectory
#mv exclude1 exclude2 /home/
#cp mydirectory destination_folder/
#cd /home/
#mv eclude1 exclude2 mydirectory/

About the usage of linux command "xargs"

I have some file like
love.txt
loveyou.txt
in directory useful; I want to copy this file to directory /tmp.
I use this command:
find ./useful/ -name "love*" | xargs cp /tmp/
but is doesn't work, just says:
cp: target `./useful/loveyou.txt' is not a directory
when I use this command:
find ./useful/ -name "love*" | xargs -i cp {} /tmp/
it works fine,
I want to know why the second works, and more about the usage of -i cp {}.
xargs puts the words coming from the standard input to the end of the argument list of the given command. The first form therefore creates
cp /tmp/ ./useful/love.txt ./useful/loveyou.txt
Which does not work, because there are more than 2 arguments and the last one is not a directory.
The -i option tells xargs to process one file at a time, though, replacing {} with its name, so it is equivalent to
cp ./useful/love.txt /tmp/
cp ./useful/loveyou.txt /tmp/
Which clearly works well.
When using the xargs -i command, {} is substituted with each element you find. So, in your case, for both "loveyou.txt" and "love.txt", the following command will be run:
cp ./useful/loveyou.txt /tmp/
cp ./useful/love.txt /tmp/
if you omit the {}, all the elements you find will automatically be inserted at the end of the command, so, you will execute the nonsensical command:
cp /tmp/ ./useful/loveyou.txt ./useful/love.txt
xargs appends the values fed in as a stream to the end of the command - it does not run the command once per input value. If you want the same command run multiple times - that is what the -i cp {} syntax is for.
This works well for commands which accept a list of arguments at the end (e.g. grep) - unfortunately cp is not one of those - it considers the arguments you pass in as directories to copy to, which explains the 'is not a directory' error.
The first example will do this:
cp /tmp/ love.txt loveyou.txt
Which can't be done, since they attempt to copy the directory /tmp and the file love.txt to the file loveyou.txt.
In the second example, -i tells xargs to replace every instance of {} with the argument, so it will do:
cp love.txt /tmp/
cp loveyou.txt /tmp/
find ./useful/ -name "love*" | xargs cp -t /tmp/
You might avoid xargs that way:
find ./useful/ -name "love*" -exec sh -c 'cp "$#" /tmp' sh {} +

Resources