For loop in bash [duplicate] - linux

This question already has answers here:
How to loop through a directory recursively to delete files with certain extensions
(16 answers)
BASH: Writing a Script to Recursively Travel a Directory of N Levels
(2 answers)
Closed 4 years ago.
I'm trying to write a bash script that recursively goes through files in a directory, writing the file's name and hexdump to a file. My current script:
#/bin/sh
touch hexdump.txt
for filename in logical/*; do
echo "$filename"
"$filename" >> hexdump.txt
hd /logical/"$filename" >> hexdump.txt
done
The current output is:
logical/*
./hexadecimalExtraction.sh: line 5: logical/*: No such file or directory
hd: /logical/logical/*: No such file or directory
How do i get it to interpret "logical/*" as the list of files within "logical" directory and not the filename itself???

"$filename" >> hexdump.txt
should probably be removed
Otherwise you are trying to run the filename itself.
Also you are looking for files in logical subdirectory in the current directory, but the trying to look in /logical/

You can't recurse with for filename in logical/*. In order to recurse, you have to use find.
To make find visit only files, not directories, use find -type f.
I don't know hd, but you probably want
find tutorials -type f | while read i; do
echo $i >> hexdump.txt
hd $i >> hexdump.txt
done

You're looking for the ** glob operator.
shopt -s globstar nullglob
for filename in logical/**/*; do
echo "$filename"
hd "$filename"
done >> hexdump.txt
filename will contain the full name of the matched files, which already includes the directory logical and any sub directories.

Related

Rename a portion of a filename recursively throughout directory and sub directory [duplicate]

This question already has answers here:
Rename files and directories recursively under ubuntu /bash
(8 answers)
Closed 1 year ago.
How can I make this command also execute throughout sub directories?
for filename in *foo*; do mv "$filename" "${filename//foo/bar}"; done
Probably you want to rename only the filename (last pathname component), not a inbetween subdirectory name. Then this task can be accomplished using globstar feature of bash.
#!/bin/bash
shopt -s globstar
for pathname in ./**/*foo*; do
[[ -f $pathname ]] || continue
basename=${pathname##*/}
mv "$pathname" "${pathname%/*}/${basename//foo/bar}"
done

Issue with grep merged with IF under linux [duplicate]

This question already has answers here:
When are square brackets required in a Bash if statement?
(3 answers)
Closed 2 years ago.
Hi I am trying to use grep with if and if the value is found under the directory it should update the file name with "_1" else copy to other directory
cd /home/inbound/ftp
f3=822220222 #ordernumber which change every time for this instance we use this
if [ grep -lq $f3 ]; then
f4=`find . -name *$f3*` #trying to get the existing file name if available
mv "$f4" "$f4_1" #updating existing file with "_1"
else
cp $file /home/outbound/ftp
grep command can be used to search a pattern in a file or an output. it can be connected to ls with a pipe to check this. However for your scenario the below would be an better alternative to find if the file is present
cd /home/inbound/ftp
f3=822220222 #ordernumber which change every time for this instance we use this
if [ -f "*$f3*" ]; then
f4=`find . -name *$f3*` #trying to get the existing file name if available
mv "$f4" "$f4_1" #updating existing file with "_1"
else
cp $file /home/outbound/ftp
However this checks for your order number in the variable f3. However you already know the filename that you are going to copy. so you can use that instead of f3.
cd /home/inbound/ftp
filename=`basename $file` #file name of the File being FTPed
if [ -f $filename ]; then
mv "$filename" "$filename_1" #updating existing file with "_1"
fi # closing this here will make sure the file gets copied all the time
cp $file /home/outbound/ftp

for loop in Linux treats pattern as filename when no files exist

I ran the following in a directory with no files:
for file in *.20191017.*;do echo ${file}; done
what it returned was this:
*.20191017.*
which is little awkward since this was just a pattern and not the filename itself.
Can anyone please help on this?
Found the reason for this anomaly (source: https://www.cyberciti.biz/faq/bash-loop-over-file/)
You can do filename expansion in loop such as work on all pdf files in current directory:
for f in *.pdf; do
echo "Removing password for pdf file - $f"
done
However, there is one problem with the above syntax. If there are no pdf files in current directory it will expand to *.pdf (i.e. f will be set to *.pdf”). To avoid this problem add the following statement before the for loop:
#!/bin/bash
# Usage: remove all utility bills pdf file password
shopt -s nullglob # expands the glob to empty string when there are no matching files in the directory.
for f in *.pdf; do
echo "Removing password for pdf file - $f"
pdftk "$f" output "output.$f" user_pw "YOURPASSWORD-HERE"
done
The for loop simply iterates over the words between in and ; (possibly expanded by bash). Here, file is just the variable name. If you want to iterate between all files that are actually present, you can, for example, add a if to check if the ${file} really exists:
for file in *.20191017.*
do
if [ -e "${file}" ]
then
echo ${file}
fi
done
Or you can use, e.g., find
find . -name '*.20191017.*' -maxdepth 1
-maxdepth 1 is to avoid recursion.

star wildcard in bash [duplicate]

This question already has answers here:
Rename multiple files in shell [duplicate]
(4 answers)
Closed 4 years ago.
I've got a small problem with my bash script. I try to change file name in current directory for whole files with txt extension to text extension. For exampel 1.txt to 1.text
My script looks like this now:
#!/bin/bash
FILES=`ls /home/name/*.txt`
NAME=*.txt
RENAME=*.text
for file in FILES
do
mv $NAME $RENAME
done
i try whole combination with single, double quotes and backticks and I receive errors all the time.
Do you have some ideas how to receive wildcards "*" in bash?
Thanks.
That's not at all how you do that.
#!/bin/bash
shopt -s nullglob
OLD=.txt
NEW=.text
FILES=(/home/name/*"$OLD")
for file in "${FILES[#]}"
do
mv "$file" "${file%$OLD}$NEW}"
done
There are a number of issues with your script. Firstly, you shouldn't run ls and attempt to store its output like that. If you want to iterate through those file, just do it in the loop:
for file in /home/name/*.txt
Now the shell is doing all the work for you, and as a bonus handling any kind of weird filenames that you might have.
In your example you were looping over the literal string "FILES", not the variable, but I guess that was just a typo.
The built-in way to change the filename is to use a parameter expansion to remove the old one, then concatenate with the new one:
old=txt
new=text
for file in /home/name/*"$old"
do
mv "$file" "${file%$old}$new"
done
If it is possible that there are no files matching the glob, then by default, the /home/name/*.txt will not be expanded and your loop will just run once. then you have a couple of options:
use shopt -s nullglob so that /home/name/*.txt expands to null, and the loop is skipped
add an explicit check inside the loop to ensure that $file exists before trying to mv:
for file in /home/name/*"$old"
do
[ -e "$file" ] || continue
mv "$file" "${file%$old}$new"
done
You can use rename to rename filenames.
rename .txt .text /home/name/*.txt
And if you want to do this by looping, you can
for FILE in /data/tmp/*.txt; do
mv "${FILE}" "${FILE/.txt/.text}"
done

how to delete filename's specific suffix in a dir, in linux [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Extract filename and extension in bash
Linux: remove file extensions for multiple files
For example, A.txt B.txt, I want to rename then to A and B .
How can I do it with shell script? Or other method ? Thanks.
for i in *.txt; do mv "$i" "${i%.txt}"; done
I would use something like:
#!/bin/bash
for file in *.txt
do
echo "$file" "$( echo $file | sed -e 's/\.txt//' )"
done
Of course replace the two above references of ".txt" to whatever file extension you are removing, or, preferably just use $1 (the first passed argument to the script).
Michael G.
for FILE in *.txt ; do mv -i "$FILE" "$(basename "$FILE" .txt)" ; done

Resources