How can I make a valid concatenated full file path? - bash

How can I make a valid constructed full file path for copy command?
I want to construct a valid file path that Will be read it by cp command as a path, where my lost file is located at, and Will be copied to another directory. The problem is that cp command doesnt recognize it as a path. I hope and appreciate, you can help me solving this problem.
*The file and directory exists.
*The full file path were constructed by concatenating $fname and $path.
*My lost file is named 12345678.xml
script
17 for((i=0;i<${#array[#]}-1;i+=2));do
18 path=$(find "/path/sourcefolder" -name "*zipfolder*" -exec grep -l "Mylostfile" {} + )
19 fname=$(find "/path/sourcefolder" -name "*zipfolder*" -exec unzip -l {} \; | grep "12345678.xml" | awk ' { printf $4 }')
20 fullpath="$path/$fname"
21 cp -t "/path/Desktop" "$fullpath"
22 done
Actual output
Test_v2.sh: line 20: /path/zipfolder/12345678.xml: No such file or directory
cp: cannot stat '': No such file or directory
Desired output
Copy the file in another directory
Additional comments #1:
I added set -xv an this is the result.
++ find /path/sourcefolder -name '*zipfolder*' -exec grep -l 12345678 '{}' +
+ path=/path/sourcefolder/zipfolder.zip
++ find /path/sourcefolder -name '*zipfolder*' -exec unzip -l '{}' ';'
++ grep 12345678
++ awk ' { printf $4 }'
+ fname=12345678.xml
+ set -xv
+ fullpath=
+ /path/sourcefolder/zipfolder.zip/12345678.xml
Test_v2.sh: line 21: /path/sourcefolder/zipfolder.zip/12345678.xml: No such file or directory
+ cp -t /path/Desktop ''
+ cp: cannot stat '': Not a directory
Additional comments #2:
The space between fullpath= and "$path/$fname" is eliminated as suggested and this is the following result.
++ find /path/sourcefolder -name '*zipfolder*' -exec grep -l 12345678 '{}' +
+ path=/path/sourcefolder/zipfolder.zip
++ find /path/sourcefolder -name '*zipfolder*' -exec unzip -l '{}' ';'
++ grep 12345678
++ awk ' { printf $4 }'
+ fname=12345678.xml
+ set -xv
+ fullpath=/path/sourcefolder/zipfolder.zip/12345678.xml
+ cp -t /path/Desktop ''
+ cp: cannot stat '/path/sourcefolder/zipfolder.zip/12345678.xml': Not a directory

It looks like what you want to do could be simply implemented as follows :
find "/path/sourcefolder" -name "*zipfolder*" -exec unzip -p {} '*12345678.xml' > "/path/Desktop/12345678.xml" \;
It extracts a file 12345678.xml from anywhere in the found zip to /path/Desktop/12345678.xml by using unzip's -p flag to print the content of the file to stdout and redirecting stdout to the target file.

Related

Copy file into directories, and change text inside file to match index of directory

I have the following files in a directory: text.txt and text2.txt
My goal is to:
1) copy these two files into non-existing directories m06/, m07/...m20/.
2) Then, in the file text.txt, in the line containing the string mlist 06 (all the files will contain such a string), I wish to change the "06" to match the index of the directory name (for example, in m13, that line in the text.txt file would be mlist 13.
For goal 1), I got the following script which works succesfully:
#!/bin/bash
mkdir $(printf "m%02i " $(seq 6 20))
find . -maxdepth 1 -type d -name 'm[0-9][0-9]' -print0 | xargs -0 -I {} cp text.txt {}
find . -maxdepth 1 -type d -name 'm[0-9][0-9]' -print0 | xargs -0 -I {} cp text2.txt {}
For goal 2), I wish to implement a command similar to
sed -i -e '/mlist/s/06/index/' ./*/text.inp
where index would correspond to the name of the directory (i.e. index = 13 in the m13/directory).
How can I make the sed command replace 06 with the correct "index" corresponding to the name of the directory?
This would probably be easier to manage if you used loop syntax instead of one-liners:
#!/bin/sh
for i in $(seq 6 20); do
# Add a leading 0 and generate the directory name
i_z=$(printf "%02d" "$i")
dir="m${i_z}"
# Create dir
mkdir -p "$dir"
# Copy base files into dir
cp test.txt test2.txt "$dir"
# Edit the index in the files to match the dir index
sed -i -e "s/mlist.*/mlist $i_z/g" \
"${dir}/test.txt" "${dir}/test2.txt"
done

Find the file path of a specific file inside a zipped folder

I'm struggling with my script. I want to find the full file path of a specific file, just like this example:
/path/folder_06may2017.zip/file_B.txt
I hope you can help me solving this problem. It will be really useful.
Directory and file samples
- Folder_01may2017.zip
+ file_A.txt
+ file_B.txt
- Folder_06may2017.zip
+ file_A.txt
+ file_B.txt
I have used this commands with no success at all:
1st attempt:
find "/path/folder/" -name "*06may2017*" -print -exec unzip -l {} \; | grep -i 'file_B'
1st Output:
182118 2017-05-06 11:20 file_B.txt
2nd attempt:
find "/path/folder/" -name "*06may2017*" -print -exec unzip -l {} \; | grep -i 'file_B'| awk '{ print $4 }' ${PWD}
2nd output:
awk: warning: command line argument '/path/folder' is a directory: skipped
3rd attempt:
find "/path/folder" -name "*06may2017*" -exec grep -l "file_B" /dev/null '{}' \;
3rd output
/path/folder/Folder_06may2017.zip
What about:
$ find "/path/folder" -name "*06may2017*" -exec unzip -l {} \; | awk '$1 ~ /Archive/{zipname = $2}; $4 ~ /file_B/ {printf "%s/%s\n", zipname, $4}'

Rename files to unique names and move them into a single destination directory

i have 100s of directories with same filename of content.html along with other files.
I am trying to copy all these content.html files under 1 directory, but since they have same name, it overwrites each other
so how can i rename and move all these under 1 directory
Eg:
./0BD3D9D2-F8B1-4472-95C2-13319650A45C:
card.png content.html note.xhtml quickLook.png snippet.txt
./0EA34DB4-CD56-42BE-91DA-F631E44FB6E0:
card.png content.html note.xhtml quickLook.png related snippet.txt
./1A33F29E-3938-4C2F-BA99-6B98FD045742:
card.png content.html note.xhtml quickLook.png snippet.txt
command i tried:
rename content.html to content
find . -type f | grep content.html | while read f; do mv $f ${f/.html/}; done
append number to filename "content" to make it unique
find . -type f | grep content | while read f; do i=1; echo mv $f $f$i.html; i=i+1; done
MacBook-Pro$ find . -type f | grep content | while read f; do i=1; echo mv $f $f$i.html; i=i+1; done
mv ./0BD3D9D2-F8B1-4472-95C2-13319650A45C/content ./0BD3D9D2-F8B1-4472-95C2-13319650A45C/content1.html
mv ./0EA34DB4-CD56-42BE-91DA-F631E44FB6E0/content ./0EA34DB4-CD56-42BE-91DA-F631E44FB6E0/content1.html
mv ./1A33F29E-3938-4C2F-BA99-6B98FD045742/content ./1A33F29E-3938-4C2F-BA99-6B98FD045742/content1.html
once above step is successful, i should be able do this to achieve my desired output:
find . -type f | grep content | while read f; do mv $f ../; done
however, i am sure i can do this in 1 step command and also my step 2 is not working (incrementing i)
any idea why step2 is not working??
bash script:
#!/bin/bash
find . -type f -name content.html | while IFS= read -r f; do
name=$(basename $f)
((++i))
mv "$f" "for_content/${name%.*}$i.html"
done
replace for_content with your destination folder name
Suppose in your base directory, you create a folder named final for storing
content.html files, then do something like below
find . -path ./final -prune -o -name "content.html" -print0 |
while read -r -d '' name
do
mv "$name" "./final/content$(mktemp -u XXXX).html"
# mktemp with -u option just creates random characters, or it is just a dry run
done
At the end you'll get all the content.html files under ./final folder in the format contentXXXX.html where XXXX are random characters.
Note:-path ./final -prune -o in find prevents it from descending to our results folder.
The inode of the of the files should be unique and so you could use the following:
find $(pwd) -name "content.html" -printf %f" "%i" "%p"\n" | awk '{ system("mv "$3" <directorytomoveto>"$2$1) }'
I'd use something like this:
find . -type f -name 'test' | awk 'BEGIN{ cnt=0 }{ printf "mv %s ./output-dir/content_%03d.txt\n", $0, cnt++ }' | bash;
You can replace ./output-dir/ with your destination directory
Example:
[root#sl7-o2 test]# ls -R
.:
1 2 3 output-dir
./1:
test
./2:
test
./3:
test
./output-dir:
[root#sl7-o2 test]# find . -type f -name 'test' | awk 'BEGIN{ cnt=0 }{ printf "mv %s ./output-dir/content_%03d.txt\n", $0, cnt++ }' | bash;
[root#sl7-o2 test]# ls ./output-dir/
content_000.txt content_001.txt content_002.txt
You can use shopt -s globstar to grab all content.html files recursively and then use a loop to rename them:
#!/bin/bash
set -o globstar
counter=0
dest_dir=/path/to/destination
for f in **/content.html; do # pick up all content.html files
[[ -f "$f" ]] || continue # skip if not a regular file
mv "$f" "$dest_dir/content_$((++counter).html"
done

Differential backup issue using comparison with md5sum in shell script

Hello I have a quick question. I am trying to implement a differential backup but where I am having trouble is comparing the hash from md5sum.txt to diffmd5.txt
I am getting the following error:
Currently the command runs and gives no errors but files are not being replaced and not backing up any files
#!/bin/bash
bkdest="/home/user/backup/differential/backup_diff"
bksource="/home/user/Documents"
destgen=`find $bkdest/* -exec md5sum {} + > diffmd5.txt`
sourcegen=`find $bksource/* -exec md5sum {} + > md5sum.txt`
$sourcegen
$destgen
$(cat diffmd5.txt) | while read f;
do
if [ $(grep f md5sum.txt | wc -l) -lt 1 ]
then
# Code to backup the file that has changed or is not on record
cp $(cut -d ' ' -f2-- <<< $f) $bkdest
fi
done
# Afterwards, update md5hashes to list newly backed up files
$sourcegen
Please help me out on figuring out where I went wrong. Thank you!
Guess this is my error when running in debug mode
Try 'cp --help' for more information.
grep: md5sum.txt: No such file or directory
cut: invalid byte, character or field list
Try 'cut --help' for more information.
cp: missing destination file operand after ‘/home/dmitriy/backup/differential/backup_diff’
Lets try with:
#!/bin/bash
bkdest="/home/user/backup/differential/backup_diff"
bksource="/home/user/Documents"
cd $bkdest
find . -type f -exec md5sum {} \; > /tmp/md5dest.txt
cd $bksource
find . -type f -exec md5sum {} \; | while read c f; do
if fgrep "$c" /tmp/md5dest.txt | fgrep -q "$f"; then
echo "$f" ignored
else
cp $f $bkdest
fi
done

How to remove files starting with #! or ending with .sh in the name

I am new to shell programming. I want to move any executable file, any file starting with shebang(#!), and any file whose name ends with .sh from a directory to /tmp/backup and log the names of the files moved.
This is what I have done till now
Searching for files with #^
grep -ircl --exclude=*.{png,jpg,gif,html,jar} "^#" /home
Finding executables
find . -type f -perm +111 or find . -type f -perm -u+x
Now I am struggling how to club these two commands get a final output which I can pass to perform backup and remove from current directory
Thanks
Use the xargs command
"find command" | xargs "grep command"
You could put everything in a file, sort it, then process it with Awk:
# Select all files to move
grep -ircl --exclude=*.{png,jpg,gif,html,jar} '^#\!' /home > list.txt
find /home -type f \( -perm -u+x -o -name "*.sh" \) -print >> list.txt
# Feed them to Awk that will log and move the file
sort list.txt | uniq | awk -v LOGFILE="mylog.txt" '
{ print "Moving " $0 >> LOGFILE
"mv -v --backup \"" $0 "\" /tmp/backup" | getline
print >> LOGFILE }'
EDIT: you can make a formal script out of this skeleton, by adding some variables and some additional checks:
#!/bin/bash
LIST="$( mktemp || exit 1 )"
LOG="/tmp/mylog.txt"
SOURCE="/home"
TARGET="/tmp/backup"
mkdir -p "${TARGET}"
cd "${SOURCE}" || exit 1
# Select all files to move
grep -ircl --exclude=*.{png,jpg,gif,html,jar} '^#\!' "${SOURCE}" > "${LIST}"
find "${SOURCE}" -type f \( -perm -u+x -o -name "*.sh" \) -print >> "${LIST}"
# Feed them to Awk that will log and move the file
sort "${LIST}" | uniq | awk -v LOGFILE="${LOG}" -v TARGET="${TARGET}" '
{ print "Moving " $0 >> LOGFILE
"mv -v --backup \"" $0 "\" " TARGET | getline
print >> LOGFILE }'

Resources