Moving .png files with mv and wildcards error - terminal

I've got a folder full of thousands of pictures. I want to move all of the .png files back one directory.. I tried
mv -i *.png ../
But get the following error:
mv: invalid option -- 'p'
Try `mv --help' for more information.
Any advice?

in order to prevent mv from trying to interpret a file with a leading dash (e.g. -pbla.png) as an option (like -p bla.png), you can separate the flags from the files using a double dash --:
mv -i -- *.png ../
another simple way is to prefix the current path ./ to each filename:
mv -i ./*.png ../

mv *.png ../
This works on every linux distribution.

Related

usage error when moving files of one extension to a directory

I have files with extension .mp3 that are in different folders within a directory, and I need to move them all to one directory to work with. I have looked at multiple tutorials and questions on SO, and no matter what I try, I either get
usage: mv [-f | -i | -n] [-v] source target
mv [-f | -i | -n] [-v] source ... directory
or "No such file or directory".
There are way too many to into each individual folder, but for now I cd into one of the folders. With this:
mv *.mp3 /Users/myname/Volumes/LaCie/model/folder/media
I get the "usage" error above. I looked at Moving files to a directory and tried:
find . | grep ".mp3" | xargs mv /Users/myname/Volumes/LaCie/model/folder/media
and get same error.
What am I doing wrong? What is the correct syntax? Also, will I be able to extract the mp3 files and move them if I'm in a directory that contains the directory with the files, but not in that directory itself? I appreciate insights into this. Thanks.
EDIT: A major part of this issue was that the path when using /Volumes starts with /Volumes. I was doing /Users/myname/Volumes and that was one reason I had so much trouble.
The problem with the way you're using xargs is that by default, xargs will append the arguments to the end of the command string you've provided it. So you'll end up running a bunch of mv commands that look like this:
mv /Users/myname/Volumes/LaCie/model/folder/media foo.mp3
You can fix that by telling xargs where to place the arguments within the command:
<other commands> | xargs -I{} mv {} /Users/myname/Volumes/LaCie/model/folder/media
The -I option lets you provide any arbitrary string as a placeholder for where the args should go. I used {} just because that seems to be the conventional token that you see used in similar contexts (such as with the -exec option of find, as shown below).
But there's an easier way to do it, using the find command's -exec option:
find . -name '*.mp3' -exec mv {} /Users/myname/Volumes/LaCie/model/folder/media \;
Also note the -name '*.mp3' part, which lets you get rid of the | grep ".mp3" part.
Lastly, just to be safe, I'd personally put a / at the end of your destination path. If the media directory doesn't exist in /Users/myname/Volumes/LaCie/model/folder, or if a non-directory item (such as a regular file or a symlink) named media exists in that location, then the find command above will happily just move all your mp3 files, one at a time, to that folder, creating a file named media there each time. And you will have lost all of your mp3 files except for the last one, which will now be a file named media.
However, with a trailing /, if media is not a directory, the mv commands will fail with an error saying so. So the revised command would be:
find . -name '*.mp3' -exec mv {} /Users/myname/Volumes/LaCie/model/folder/media/ \;
Update: Per Gordon Davisson's comment below, you should also consider adding -i or -n to the mv command, to avoid accidentally overwriting files with duplicate names. For example, if you have a/foo.mp3 and b/foo.mp3, the above command will overwrite one with the other. The -i option will cause mv to prompt you to confirm each file move, whereas the -n option (a.k.a. --no-clobber) will prevent mv from overwriting a file if a file with the same name already exists.
There are different implementations and versions of mv. You can check the allowed syntax of your version using man mv.
If you have GNU mv you could use mv -t target/dir *.mp3.
Most implementations should support mv *.mp3 target/dir.
If your mv only supports the absolute minimum of mv source target with exactly one source and one target file you can use the following command which should always work if target/dir/ exists.
for i in *.mp3; do mv "$i" "target/dir/$i"; done

Bash Extract tar.gz file

I have my tar file under:
/volume1/#appstore/SynoDSApps/archiv/DE/2018_08_18__Lysto BackUp.tar.gz
With the tar command:
tar -tf "/volume1/#appstore/SynoDSApps/archiv/DE/2018_08_18__Lysto BackUp.tar.gz"
The command show me:
/volume1/02_public/3rd_Party_Apps/SPK_SCRIPTS/SynoDSApps/webapp/
/volume1/02_public/3rd_Party_Apps/SPK_SCRIPTS/SynoDSApps/webapp/exit_codes/
/volume1/02_public/3rd_Party_Apps/SPK_SCRIPTS/SynoDSApps/webapp/exit_codes/code_FUNC
/volume1/02_public/3rd_Party_Apps/SPK_SCRIPTS/SynoDSApps/webapp/exit_codes/code_SCRI
/volume1/02_public/3rd_Party_Apps/SPK_SCRIPTS/SynoDSApps/webapp/login/
/volume1/02_public/3rd_Party_Apps/SPK_SCRIPTS/SynoDSApps/webapp/login/check_appprivilege.php
/volume1/02_public/3rd_Party_Apps/SPK_SCRIPTS/SynoDSApps/webapp/login/check_login.php
/volume1/02_public/3rd_Party_Apps/SPK_SCRIPTS/SynoDSApps/webapp/login/privilege.php
/volume1/02_public/3rd_Party_Apps/SPK_SCRIPTS/SynoDSApps/webapp/scripte/
/volume1/02_public/3rd_Party_Apps/SPK_SCRIPTS/SynoDSApps/webapp/scripte/Lysto BackUp/
/volume1/02_public/3rd_Party_Apps/SPK_SCRIPTS/SynoDSApps/webapp/scripte/Lysto BackUp/sys
/volume1/02_public/3rd_Party_Apps/SPK_SCRIPTS/SynoDSApps/webapp/scripte/Lysto BackUp/sys_func
/volume1/02_public/3rd_Party_Apps/SPK_SCRIPTS/SynoDSApps/SSH_ERROR
My Plan or better my wish is to handle it like this:
IFS=$'\n'
for PATHS in $(tar -tPf "/volume1/#appstore/SynoDSApps/archiv/DE/2018_08_18__Lysto BackUp.tar.gz")
do
SED=$(echo "$PATHS" | sed 's/.*\///')
if [[ -n "$SED" ]]
then
tar -C "${target_archiv}" -xvf "/volume1/#appstore/SynoDSApps/archiv/DE/2018_08_18__Lysto BackUp.tar.gz" "$PATHS"
#echo JA
echo "$PATHS"
fi
done
unset IFS
i only want one file of the tar and Store this to a different Directory....
but this command with the -C don´t work... it Extract all the files of the tar....
My Question is, is it possible to extract only one file of the Tar without cd to the Directory ??
Another Question: is it possible to Extract only the files of the tar without the Folders this is maybe the better way but I don´t know how...?
and no I can not tar the files without the paths of it I need them...
so this is no way for me...
I hope for help here :)
If your ultimate goal is to extract files without the full path, you can use a SED-like expression to rename the files while they are extracted, using the --xform option:
tar -C "${target_archiv}" -xvf "/volume1/#appstore/SynoDSApps/archiv/DE/2018_08_18__Lysto BackUp.tar.gz" --xform='s,^.*/,,'
The 's,^.*/,,' expression asks to substitute (s) from the beginning of the filename (^), capture everything (.*) and stop at the last slash (/) then replace it with nothing. In other words, it removes the directory structure from the filenames.
If you want to get rid of the empty folders that have been extracted, you may call this command after extracting:
find "${target_archiv}" -mindepth 1 -maxdepth 1 -type d -exec rmdir {} \;
Keep in mind it will remove all the (empty) subfolders of "${target_archiv}", even the ones that were already here before extracting the tarball. However, because rmdir will not remove directories that contain files, it will be mostly harmless to the subdirectories you had.

How to retain folder structure in bash scripting?

I made a program to convert the bitrate of music. The program is as follows..
for f in *.mp3 ;
do lame --mp3input -b $bitrate "$f" $path_to_destination/"$f" ;
done;
But this works for only one folder; I have music in different folders. How to modify the code so that it can recursively make conversions happen yet retain the folder structure in the output?
If you have a new enough Bash (version 4.3 works; version 3.x does not), you can use:
shopt -s globstar nullglob
for file in *.mp3 **/*.mp3
do
lame --mp3input -b $bitrate "$file" "$path_to_destination/$file"
done
The globstar option means that the ** notation works recursively; the nullglob option means that if there are no .mp3 files in any of the subdirectories (or no sub-directories), you get nothing generated instead of a name **/*.mp3 which would happen by default.
Because this uses globbing, it is safe even with paths or file names that contain spaces, newlines or other awkward characters.
If the sub-directories don't necessarily exist under $path_to_destination, then you need to create them. Add:
mkdir -p $(dirname "$path_to_destination/$file")
before the invocation of lame. This creates all the missing directories on the path leading to the target file (no error if all the directories already exist), leaving lame to create the file in that directory.
find . -type f -name '*.mp3' | while IFS= read -r src
do
dst="$path_to_destination/$src"
mkdir -p $(dirname "$dst")
lame --mp3input -b $bitrate "$src" "$dst"
done

Copy all files in directory except ".txt" and not to replace existing files

i have to copy all the file from source directory to destination directory , but skip all file with extension ".txt" and not to the replace the file if its already present in destination directory
example
source directory
/a/aone.js
/a/atwo.js
/b/bone.txt
/b/btwo.js
destination directory
/a/atwo.js
then it should only copy
/a/aone.js
/b/btwo.js
and skip "/a/atwo.js" because its already present in destination folder
and skip "/b/bone.txt" because its extension is ".txt"
i tried this command but this does not work
find /path/to/source/ \( ! -name "*.txt" \) -type f | cp -n /path/to/destination/ -R
cp -n /path/to/source/*(!*.txt) /path/to/destination/ -R
Assuming you can use rsync, (vaz is verbose, archive and compress - I believe the other options are self explanatory)
rsync -vaz --exclude "*.txt" /path/to/source/ /path/to/destination/
Why make it difficult. You were on the right track. A simple:
cp -an /path/to/source/*.[^t*] /path/to/destination
will copy all files from source, except those whose extension begins with a t to destination. It will do so without overwriting existing files in destination. This presumes that files do not have more than one dot. If so, then a few more lines of code will be needed.
The following will illustrate use of the above:
$ md tmp
$ md a
$ md b
$ touch a/a.{j,k,l,txt}
$ ls -1 a
a.j
a.k
a.l
a.txt
$ cp -an a/a*.[^t*] b
$ ls -1 b
a.j
a.k
a.l
using cp, you must match the proper directory depth. If you have another intervening directory, then simply add an additional wildcard. For example:
$ ls -1 dat/*/*.[^t*]
dat/a/a.j
dat/a/a.k
dat/a/a.l
dat/b/a.j
dat/b/a.k
dat/b/a.l
If your directory structure gets more complex, then go with find or rsync. Both are excellent tools and rsync can handle both local and network transfers. cp is the right tool for small jobs, but when more flexibility is needed, then grab a bigger hammer.

cp: silence "omitting directory" warning

I'm using the command cp ./* "backup_$timestamp" in a bash script to backup all files in directory into a backup folder in a subdirectory. This works fine, but the script keeps outputting warning messages:
cp: omitting directory `./backup_1364935268'
How do I tell cp to shut up without silencing any other warnings that I might want to know about?
The solution that works for me is the following:
find -maxdepth 1 -type f -exec cp {} backup_1364935268/ \;
It copies all (including these starting with a dot) files from the current directory, does not touch directories and does not complain about it.
Probably you want to use cp -r in that script. That would copy the source recursively including directories. Directories will get copied and the messages will disappear.
If you don't want to copy directories you can do the following:
redirect stderr to stdout using 2>&1
pipe the output to grep -v
script 2>&1 | grep -v 'omitting directory'
quote from grep man page:
-v, --invert-match
Invert the sense of matching, to select non-matching lines.
When copying a directory, make sure you use -R
cp -R source source_duplicate_copy_name
-R, -r, --recursive copy directories recursively
--reflink[=WHEN] control clone/CoW copies. See below
--remove-destination remove each existing destination file before
attempting to open it (contrast with --force)
--sparse=WHEN control creation of sparse files. See below
--strip-trailing-slashes remove any trailing slashes from each SOURCE

Resources