bash copy with variable - bash

I'm trying to copy files to the current directory using a bash script.
In order to handle paths that need escaping a variable is used that is escaped and then supplied to the cp command.
The cp command is complaining with:
usage: cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file target_file
cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file ... target_directory
I know what that means but I cannot understand why that happens.
Here is the code:
z="/a/b/c d (e) f.txt"
y=`printf %q "$z"`
cp $y x.txt # not working as expected
echo cp $y x.txt # output is "cp /a/b/c\ d\ \(e\)\ f.txt x.txt"

Note: When you are in trouble with a bash script, you should run it with the -x option as it provides a first level of debugging.
The escaping of the filename is incorrect. You should use:
cp "$z" x.txt

You can avoid y altogether and use quotes:
cp "$z" x.txt
This is because tokenization occurs after variable substitution. Another possibility is to change the field separator:
IFS="" # Set special variable denoting field separator (defaults to whitespace).
cp $y x.txt # Works as you intended.

Related

MacOS bash script not honoring double quotes

I have a build script in which I'm trying to copy a file into a directory with spaces. My code works fine when the line is written as such:
cp test.png My\ Program.app/Contents/Resources
but when it's instead written as:
cp test.png “My Program.app/Contents/Resources”
...it fails with an error:
usage: cp [-R [-H | -L | -P]] [-fi | -n] [-apvXc] source_file target_file
cp [-R [-H | -L | -P]] [-fi | -n] [-apvXc] source_file ... target_directory
What's wrong?
Adding set -x at the beginning of the script helped me see what was happening and identify the problem.
The problem was that there were spaces in the app bundle name (e.g. "My Program"), and enclosing the path in single or double quotes didn't work -- because the text editor I was using changed double quotes into smart quotes.
What also worked was escaping the spaces with a backslash, like this:
GOOD:
cp -f myfile My\ Program.app/Contents/Resources
GOOD (but be careful; some MacOS text editors may change this to the later, BAD form automatically):
cp -f myfile "My Program.app/Contents/Resources"
BAD (due to the quotes being "smart quotes" instead of plain ASCII quotes):
cp -f myfile “My Program.app/Contents/Resources”
To explain why: Because the shell only sees regular ASCII quotes as quote characters, this gets interpreted as five arguments, instead of the intended four:
cp -f myfile '“My' 'Program.app/Contents/Resources”'
# ^^ ^^ ^^^^^^ ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# | | | | |
# 1 2 3 4 5
...and since cp only accepts more than two non-option positional arguments when the last one is a directory, but Program.app/Contents/Resources” is not a directory that actually exists, it throws a usage error.

illegal option -- ? when copying

I have just started to work on a Imac macOS HighSierra and when trying to copy some files I keep getting the error:
I just made a test directory to clarify the issue:
The directory test contains:
file1.txt file2.txt folder1
Using the following command in the parent directory:
cp -R test/ .
I get this error:
cp: illegal option -- ?
usage: cp [-R [-H | -L | -P]] [-fi | -n] [-apvXc] source_file target_file
cp [-R [-H | -L | -P]] [-fi | -n] [-apvXc] source_file ... target_directory
According to manual page for cp, the -R argument means:
If source_file designates a directory, cp copies the directory and the entire subtree connected at that point. If the source_file ends in a /, the contents of the
directory are copied rather than the directory itself.
Any suggestions as to why I get the error ?
I have bash version version 3.2.57(1)-release
----UPDATE---
According to comments to this issue, I provide some additional information:
which cp returns /bin/cp
echo cp -R test/ .returns cp -R test/ .
set | grep cp returns nothing
cp --version and cp --help returns cp: illegal option -- ? usage: cp [-R [-H | -L | -P]] [-fi | -n] [-apvXc] source_file target_file cp [-R [-H | -L | -P]] [-fi | -n] [-apvXc] source_file ... target_directory
man cp returns the manual page but it doesn't seem to depict anything about the version except BSD February 23, 2005 BSD
For Mac OS, change the cp commands as below examples
Ex 1.
"copy:schemas": "cp --parents schematics/*/schema.json ../../dist/my-lib/",
as
"copy:schemas": "find schematics -type f -name 'schema.json' -exec rsync -R {} ../../dist/my-lib/ \\;",
Ex 2.
copy:files": "cp --parents -p schematics/*/files/** ../../dist/my-lib/",
as
"copy:files": "find schematics/*/files/** -exec rsync -R {} ../../dist/my-lib/ \\;",
Hope this helps 😊.
Does this solve your issue:
cp -R test/* .
or:
cp -R test/* ./
By adding the asterisk, you mention that you are copying files, not a directory.

move all files from folder A to B whenever a certain string is present

I am trying to move files from folder A to folder B whenever a file contains a certain string:
grep -Rli '22/05/2018' ads/ | awk -F "//" '{print $2}' | xargs cp $0 projection/$1
cp: illegal option -- b
usage: cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file target_file
cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file ... target_directory
how to fix this?
Following may help you here.
grep -L -Z -r 'your_string_to_be_checked' . | xargs -0 -I{} mv {} target_directory/
Explanation:
grep -L: Means leave those files which are NOT having that specific string which we are searching for.
-Z: means output should have \0 in file names so space is not being used as delimiter.
-I{} mv {} new_directory/ means replace {} with file names and make it like mv filename new_directory and run it to move the files to new place.
I am using mv here you could use cp too here.
Not sure why you're using awk.
Solution:
grep -lir '22/05/2018' ~/ads/* | xargs cp -t $DEST_FOLDER
Source
Once you have the list of filenames you want to copy you could just use xargs -I:
$ cat listOfFileNames | xargs -I{} cp {} $destFolder
the -I option gives a name to the list of arguments, allowing you to place them wherever you want.

The command cp -r on the terminal

How could I use cp -r command to copy more directories? For example, I'd to copy awesome.txt, neat.txt in the folder something with the command cp -r awesome.txt neat.txt something, but I have an error.
Error :
usage: cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file target_file
cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file ... target_directory
Thanks!
There are several ways you could achieve this. The easiest I have seen is to use the following.
cp /home/usr/dir/{file1,file2,file3,file4} /home/usr/destination/
The syntax uses the cp command followed by the path to the directory the desired files are located in with all the files you wish to copy wrapped in brackets and separated by commas.
Make sure to note that there are no spaces between the files. The last part of the command, /home/usr/destination/, is the directory you wish to copy the files into.
or if the all the files have the same prefix but different endings you could do something like this:
cp /home/usr/dir/file{1..4} ./
Where file1,file2,file3 and file4 would be copied.

How can I copy files with names containing spaces and UNICODE, when using a shell script?

I have a list of files that I'm trying to copy and move (using cp and mv) in a bash shell script. The problem that I'm running into, is that I can't get either command to recognize a huge number of files, seemingly because the filenames contain spaces and/or unicode characters. I couldn't find any switches to decode/re-encode these characters. Instead, for example, if I copy "file name.xml", I get "*.xml" and a script error that the file wasn't found for my result. Does anyone know settings or commands that will deal with these files?
EDIT(adding current code):
When I run:
MacBookPro:Desktop$ ./script.sh
#!/bin/sh
dateVar=`date +%Y-%m-%d`
mkdir /Volumes/Documents/SMSarchive/$dateVar
cd /Volumes/Documents/SMSarchive/SMSdrop
for i in *.xml
do
cp $i /Volumes/Documents/SMSarchive/$dateVar/$dateVar-$i
done
I get the message:
usage: cp [-R [-H | -L | -P]] [-fi | -n] [-pvX] source_file target_file
cp [-R [-H | -L | -P]] [-fi | -n] [-pvX] source_file ... target_directory
...when it hits the "cp" command. There's actually more to the script, that processes the copied files further. With a "regular" file name e.g. 'file.xml', everything works fine. It's only files with spaces, or Unicode characters, where I have problems.
Problems with spaces indicates that insufficient quoting has been done. The following is incorrect:
someprogram $file
The correct version is as follows:
someprogram "$file"
watch out for code errors when $i is null!
This can be the result of fatal rm -Rf errors!
Sometimes there are easier ways than dealing with shell quoting. In your case I would use find -print0 and xargs -0. The null character termination allows you to easily manipulate strings with spaces (i.e lists of filenames).
For your example, code would look something like this:
#!/bin/sh
dateVar=`date +%Y-%m-%d`
mkdir /Volumes/Documents/SMSarchive/$dateVar
cd /Volumes/Documents/SMSarchive/SMSdrop
find . -maxdepth 1 -name '*.xml' -print0 | \
xargs -0 -I {} cp {} /Volumes/Documents/SMSarchive/$dateVar/$dateVar-{}

Resources