How to archive each file in a folder separately? - compression

I have many files in a folder. If I have a single file, 7z a -t7z archive1.zip -mx0 works fine. But my files are file1, file2 ... I want to archive these files separately like archive1.zip, archive2.zip ...
Note: File names are random and archive names don't necessarily be regular like archive2, archive3. All I want archive names must be parallel to file names. For example screenshot.jpg > screenshot.zip, book.pdf > book.zip

I think a good way to do this is using find :
find . -maxdepth 1 -type f -not -name "*.zip" -exec sh -c '7z a -t7z "${1%.*}.zip" -mx0 {}' sh {} \;
-maxdepth 1 is used to not enter subdirectories
-not -name "*.zip" is used to exclude archives
-exec sh -c '' sh {} is there just to be able to strip the extension from the filename
"${1%.*}.zip" transforms filename.extension into filename.zip

Related

How to -find -exec cp files from a list containing a portion of the filename

I've been searching for a long time and can't find an answer that works. I have a list with partial filenames (the first few letters of the filenames). If I place the file names individually as follows it works:
find ~/directory/to/search -name "filename*" -print -exec cp '{}' ~/directory/to/copyto \;
If I try to include the list in this scenario it does not:
cat ~/directory/List.txt | while read line
do
echo "Text read from file - $line"
find ~/directory/to/search -name "$line*" -type f
done
neither does this:
cat ~/directory/List.txt | while read line
do
echo "Text read from file - $line"
find ~/directory/to/search -name "$line&*" -type f
done
Ultimately, I'd like to add:
-exec cp '{}' ~/directory/to/copy/to \;
And copy over all files matching the find criteria.
I've tried using grep but the files are huge so it would take forever. I tried using all sorts of combinations of find, xargs, cp, grep and regex as read in previous searches and no luck.
Is the only solution to write a long script with a bunch of if then statements? I've been using Linux but it would be cool to use it on mac as well.
Here is a crude attempt at getting away with a single find invocation.
predicates=()
or=''
while read -r line; do
predicates+=($or -name "$line*")
or="-o"
done < ~/directory/list.txt
find ~/directory/to/search -type f \( "${predicates[#]}" \) \
-exec cp -t ~/directory/to/copy/to {} +
The array functionality requires an extended shell (Bash, ksh, etc) with this functionality; it won't work with /bin/sh.
cp -t is a GNU extension; if you don't have that, maybe just use your original -exec cp {} dir \; though it will be less efficient. Some old versions of find also don't support -exec ... +.

Filename match and export

I have several files in a folder. I have to match the filenames using a regex pattern. In the regex pattern I have a word which would be a variable. I want all the files matched with the pattern to be moved to a separate directory with an alternate filename replacing the string with which I had made the match.
Eg,
I have many files with filenames having the word foo in the directory like,
gadgeagfooafsa
fsafsaffooarwf
fasfsfoofsafff
I have to list these files and copy it to another directory replacing the word foo from it. I have specified the new pattern to be "kuh", Like the above files should be copied to the new folder as
gadgeagkuhafsa
fsafsafkuharwf
fasfskuhfsafff
Finally, can I pipe different commands together to execute these in one line? :)
I had tried this command, but it didn't work, somehow the copy is failing.
ls | grep ".*foo[} ].*" | xargs cp -t work/
find + bash solution:
find . -type f -name "*foo*" -exec bash -c 'fn=${0##*/}; cp "$0" "new_dest/${fn//foo/kuh}"' {} \;
fn=${0##*/} - extracting file basename
${fn//foo/kuh} - substituting foo with kuh in filename
Replace/adjust new_dest with your current destination directory name.
I chose /tmp as the new destination, and only used two of the example files
newdest="/tmp"; fp="foo"; np="kuh"; for f in $(find . -type f -name "*$fp*"); do new=$(echo $f| sed "s/$fp/$np/g"); cp -f $f $newdest/$new ; done
which moves and renames the files
ls /tmp/*kuh*
/tmp/fsafsafkuharwf /tmp/gadgeagkuhafsa
If all the files are in same folder
with bash
for i in *foo* ;do mv "$i" /tmp/"${i/foo/kuh}";done

How to delete selected files from the command line

I have a shell command that I run to scan my server and list all files with the name temp_file_14 in the /home directory tree as follows:
find /home . -name "temp_file_14" -exec ls -lh {} \;
I would like to change this command to have it physically delete the "found" files instead of listing them. Can someone help me with what the command should look like to perform a delete task instead of a list task?
Thanks.
This should work:
find . -name "temp_file_14" -exec rm -rf {} \;
Or this one:
find . -type f -name "temp_file_14" -exec rm -f {} \;

changing folder name recursively using regex (shell)

So I want to change the name of a specific folder recursively. However, that folder isn't always at the same depth or position. I want to change the folder name from variables to constant.
So the variables folders might be located at depth 2, and/or 3, and/or 4, and/or 5, 6, etc... I do not know that
It might be
/var/me/variables/.../.../
or
/var/me/..../..../.../variables/...
or
/var/variables/..../variables/.../../variables/
What I want again is, WHEREVER there is a folder called variables, change its name to constant
I did the following code, but it doesn't work
find var -type d -exec echo `echo "{}" | sed 's/variables/constant/g'` \;
any help would be appreciated.
Thank you!!
This is fun! Here are my two cents:
find . -depth -type d -name variables -execdir mv -T {} constant \;
Rationale:
-depth avoids changing a path find later descends into; probably can be omitted.
-execdir avoids the need to play games with entire paths, so we can operate only on the directory basename
passing the -T option to mv makes it bail if a directory constant should already exist
You actually need to call mv, not echo:
find var -type d -name "*variables*" -exec mv {} `echo "{}" | sed 's/variables/constant/g'` \;
The above assumes you have directories with with string "variables" in names. If you are after directories which are called precisely "variables", then it could be a bit simpler:
find var -type d -name variables -exec mv {} constant \;
Try this find command:
find var -name "*variables*" -type d -exec bash -c 'mv "$1" "${1//variables/constant}"' - '{}' \;
Try using find with rename
find /var -type d -name 'variables' -type d -exec rename 's/variables/constant/' {} \;

Regex to rename all files recursively removing everything after the character "?" commandline

I have a series of files that I would like to clean up using commandline tools available on a *nix system. The existing files are named like so.
filecopy2.txt?filename=3
filecopy4.txt?filename=33
filecopy6.txt?filename=198
filecopy8.txt?filename=188
filecopy3.txt?filename=19
filecopy5.txt?filename=1
filecopy7.txt?filename=5555
I would like them to be renamed removing all characters after and including the "?".
filecopy2.txt
filecopy4.txt
filecopy6.txt
filecopy8.txt
filecopy3.txt
filecopy5.txt
filecopy7.txt
I believe the following regex will grab the bit I want to remove from the name,
\?(.*)
I just can't figure out how to accomplish this task beyond this.
A bash command:
for file in *; do
mv $file ${file%%\?filename=*}
done
find . -depth -name '*[?]*' -exec sh -c 'for i do
mv "$i" "${i%[?]*}"; done' sh {} +
With zsh:
autoload zmv
zmv '(**/)(*)\?*' '$1$2'
Change it to:
zmv -Q '(**/)(*)\?*(D)' '$1$2'
if you want to rename dot files as well.
Note that if filenames may contain more than one ? character, both will only trim from the rightmost one.
If all files are in the same directory (ignoring .dotfiles):
$ rename -n 's/\?filename=\d+$//' -- *
If you want to rename files recursively in a directory hierarchy:
$ find . -type f -exec rename -n 's/\?filename=\d+$//' {} +
Remove -n option, to do the renaming.
I this case you can use the cut command:
echo 'filecopy2.txt?filename=3' | cut -d? -f1
example:
find . -type f -name "*\?*" -exec sh -c 'mv $1 $(echo $1 | cut -d\? -f1)' mv {} \;
You can use rename if you have it:
rename 's/\?.*$//' *
I use this after downloading a bunch of files where the URL included parameters and those parameters ended up in the file name.
This is a Bash script.
for file in *; do
mv $file ${file%%\?*};
done