Parsing ls, not recommended - linux

I received a advice for do not parse ls, like describes in this website: Don't parse ls.
I was looking for DAILY files in my directory so that's what I did then:
for f in *.DA*; do
[[ -e $f ]] || continue
for file in $f; do
echo "The file that you are working on: "$file
archiveContent=$( sed -n -e 1p $file )
echo $archiveContent
done
done
Ok, that's works well, I've two files A.DAILY and B.DAILY, with the both archives I can get what is inside it, but when I changed a little bit the loop, it doesn't iterated with all files with .DAILY extension in my directory.
for f in *.DA*; do
[[ -e $f ]] || continue
for file in $f; do
echo "The file that you are working on: "$file
archiveContent=$( sed -n -e 1p $file )
echo $archiveContent
COMPRESS $archiveContent;
done
done
when I called a function inside the loop, the loop just does for the first file, but not to the second.

Since the outer loop sets f to each file in turn, your inner loop doesn't seem to serve any purpose.
for f in *.DA*; do
[[ -e $f ]] || continue
echo "The file that you are working on: $f"
archiveContent=$( sed -n -e 1p "$f" )
echo "$archiveContent"
COMPRESS "$archiveContent"
done

Related

How can I remove the extension of files with a specific extension?

I'm trying to create a program that would remove the extensions of files with that specific extension in a directory.
So for instance there exists a directory d1, within that directory there are three files a.jpg, b.jpg and c.txt and the extension that I want to manipulate is .jpg.
After calling my program, my output should be a b c.txt since all files with .jpg now have jpg removed from them.
Here is my attempt to solve it so far:
#!/bin/bash
echo "Enter an extension"
read extension
echo "Enter a directory"
read directory
allfiles=$( ls -l $directory)
for x in $allfiles
do
ext=$( echo $x | sed 's:.*.::')
if [ $ext -eq $extension]
then
echo $( $x | cut -f 2 -d '.')
else
echo $x
fi
done
However, when I run this, I get an error saying
'-f' is not defined
'-f' is not defined
what should I change in my code?
You can solve your problem by piping the result of find to a while loop:
# First step - basic idea:
# Note: requires hardening
find . -type f | while read file; do
# do some work with ${file}
done
Next, you can extract a filename without an extension with ${file%.*} and an extension itself with ${file##*.} (see Bash - Shell Parameter Expansion):
# Second step - work with file extension:
# Note: requires hardening
find . -type f | while read file; do
[[ "${file##*.}" == "jpg" ]] && echo "${file%.*}" || echo "${file}";
done
The final step is to introduce some kind of hardening. Filenames may contain "strange" characters, like a new line character or a backslash. We can force find to print the filename followed by a null character (instead of the newline character), and then tune read to be able to deal with it:
# Final step
find . -type f -print0 | while IFS= read -r -d '' file; do
[[ "${file##*.}" == "jpg" ]] && echo "${file%.*}" || echo "${file}";
done
What about use mv command?
mv a.jpg a

Unix script / replace string in file from variable and move into another directory

I'm trying to do a script which find specific string in .txt files and replace by variable. I don't want to change original files but do the copies and then move into another (specific) directory. Let's assume 3 .txt files:
files.txt,
file2.txt
file3.txt
First step is to find string "string1" and "string2" in all .txt files and do the copies (eg. tmp files).
Second is to replace a string by variable $1 and $2 (working on tmp files).
Then move all of them to 'directoryname' directory.
That's what I'v got:
#!/bin/bash
echo "$1 - first parameter"
echo "$2 - second"
configurer() {
for file in *.txt
do
echo "Processing file .... $file"
orig_file=$file
tmp_file=$orig_file.tmp
cp $orig_file $tmp_file
sed "s/string1/$1/g;s/string2/$2/g" $tmp_file
mv $tmp_file directorname/$orig_file
done
}
configurer
echo "Done ..."
It's almost correct, (correct move into another directory, do the tmp files), but sed function doesn't work as it should and I have no idea why. Could anyone take a look ?
Regards
try below sed, its always problem with sed with variable
sed -i -e 's/string1/'"$1"'/g' -e 's/string2/'"$2"'/g' $tmp_file
let me know if it works
for your piece of code
#!/bin/bash
echo "$1 - first parameter"
echo "$2 - second"
configurer() {
for file in *.txt
do
echo "Processing file .... $file"
orig_file=$file
tmp_file=$orig_file.tmp
cp $orig_file $tmp_file
sed -i -e 's/string1/'"$1"'/g' -e 's/string2/'"$2"'/g' $tmp_file
mv $tmp_file directorname/$orig_file
done }
configurer $1 $2
echo "Done ..."

Using inotifywait to process two files in parallel

I am using:
inotifywait -m -q -e close_write --format %f . | while IFS= read -r file; do
cp -p "$file" /path/to/other/directory
done
to monitor a folder for file completion, then moving it to another folder.
Files are made in pairs but at separate times, ie File1_001.txt is made at 3pm, File1_002.txt is made at 9pm. I want to monitor for the completion of BOTH files, then launch a script.
script.sh File1_001.txt File1_002.txt
So I need to have another inotifywait command or a different utility, that can also identify that both files are present and completed, then start the script.
Does anyone know how to solve this problem?
I found a Linux box with inotifywait installed on it, so now I understand what it does and how it works. :)
Is this what you need?
#!/bin/bash
if [ "$1" = "-v" ]; then
Verbose=true
shift
else
Verbose=false
fi
file1="$1"
file2="$2"
$Verbose && printf 'Waiting for %s and %s.\n' "$file1" "$file2"
got1=false
got2=false
while read thisfile; do
$Verbose && printf ">> $thisfile"
case "$thisfile" in
$file1) got1=true; $Verbose && printf "... it's a match!" ;;
$file2) got2=true; $Verbose && printf "... it's a match!" ;;
esac
$Verbose && printf '\n'
if $got1 && $got2; then
$Verbose && printf 'Saw both files.\n'
break
fi
done < <(inotifywait -m -q -e close_write --format %f .)
This runs a single inotifywait but parses its output in a loop that exits when both files on the command line ($1 and $2) are seen to have been updated.
Note that if one file is closed and then later is reopened while the second file is closed, this script obviously will not detect the open file. But that may not be a concern in your use case.
Note that there are many ways of building a solution -- I've shown you only one.

Md5 Hash to identify and archive images

This is my first ever bash script and I am trying to iron out all of the creases and make the script run nicely. The script is to archive all of the specified .jpg files that it finds in multiple directories on a HDD/Flash drive. There are files with the same name but different content so I have used an Md5 sum to hash them.
I am getting the directory does not exist error in Geany but it runs fine from command bar missing out two of the images. I have tried everything I can think of to fix it. Is it messy code that is doing this?
#!/bin/sh
if [ ! -d "$1" ]; then
echo Directory "$1" cannot be found. Please try again.
exit
fi
if [ $# -eq 1 ]; then
echo "usage: Phar image_path archive_path"
exit
fi
if [ -d "$2" ]; then
echo "archive exists"
else
echo "the directory 'archive' does't exist. Creating directory 'archive'."
mkdir -p ~/archive
fi
find $1 -iname "IMG_[0-9][0-9][0-9][0-9].JPG" | cat > list.txt
[ -f ~/my-documents/md5.txt ] && rm md5.txt || break
while read line;
do md5sum $line | xargs >> md5.txt
done < list.txt
sort -k 1,1 -u md5.txt | cat > uniquemd5.txt
cut -d " " -f 2- uniquemd5.txt > uniquelist.txt
sort uniquelist.txt -r -o uniquelist.txt
for line in $(cat uniquelist.txt)
do
file=$(basename $line) path="$2/file"
if [ ! -f $path ];
then
cp $line $2
else
cp $line $path.JPG
fi
done
You haven't guarded against spaces in the folder and file names everywhere.
For instance:
cp $line $2
should be:
cp "$line" "$2"
You should start by eliminating these spaces as a source to your error by evaluating each variable you are referencing and adding ""'s.
If you still get the error please provide us with the arguments used and which directory that does not exist.

Creating a pathname to check a file doesn't exist there / Permission denied error

Hello from a Linux Bash newbie!
I have a list.txt containing a list of files which I want to copy to a destination($2). These are unique images but some of them have the same filename.
My plan is to loop through each line in the text file, with the copy to the destination occurring when the file is not there, and a mv rename happening when it is present.
The problem I am having is creating the pathname to check the file against. In the code below, I am taking the filename only from the pathname, and I want to add that to the destination ($2) with the "/" in between to check the file against.
When I run the program below I get "Permission Denied" at line 9 which is where I try and create the path.
for line in $(cat list.txt)
do
file=$[ basename $line ]
path=$[ $2$file ]
echo $path
if [ ! -f $path ];
then
echo cp $line $2
else
echo mv $line.DUPLICATE $2
fi
done
I am new to this so appreciate I may be missing something obvious but if anyone can offer any advice it would be much appreciated!
Submitting this since OP is new in BASH scripting no good answer has been posted yet.
DESTINATION="$2"
while read -r line; do
file="${line##*/}"
path="$2/$file"
[[ ! -f $path ]] && cp "$line" "$path" || mv "$line" "$path.DUP"
done < list.txt
Don't have logic for counting duplicates at present to keep things simple. (Which means code will take care of one dup entry) As an alternative you get uniq from list.txt beforehand to avoid the duplicate situation.
#anubhava: Your script looks good. Here is a small addition to it to work with several dupes.
It adds a numer to the $path.DUP name
UniqueMove()
{
COUNT=0
while [ -f "$1" ]
do
(( COUNT++ ))
mv -n "$1" "$2$COUNT"
done
}
while read -r line; do
file="${line##*/}"
path="$2/$file"
[[ ! -f $path ]] && cp "$line" "$path" || UniqueMove "$line" "$path.DUP"
done < list.txt

Resources