How to loop over files in directory and change path and add suffix to filename
A couple of notes first: when you use Data/data1.txt
as an argument, should it really be /Data/data1.txt
(with a leading slash)? Also, should the outer loop scan only for .txt files, or all files in /Data? Here's an answer, assuming /Data/data1.txt
and .txt files only:
#!/bin/bash
for filename in /Data/*.txt; do
for ((i=0; i<=3; i++)); do
./MyProgram.exe "$filename" "Logs/$(basename "$filename" .txt)_Log$i.txt"
done
done
Notes:
/Data/*.txt
expands to the paths of the text files in /Data (including the /Data/ part)$( ... )
runs a shell command and inserts its output at that point in the command linebasename somepath .txt
outputs the base part of somepath, with .txt removed from the end (e.g./Data/file.txt
->file
)
If you needed to run MyProgram with Data/file.txt
instead of /Data/file.txt
, use "${filename#/}"
to remove the leading slash. On the other hand, if it's really Data
not /Data
you want to scan, just use for filename in Data/*.txt
.
Loop through files in directory specified using argument
This would happen if the directory is empty, or misspelled. The shell (in its default configuration) simply doesn't expand a wildcard if it has no matches. (You can control this in Bash with shopt -s nullglob
; with this option, wildcards which don't match anything are simply removed.)
You can verify this easily for yourself. In a directory with four files,
sh$ echo *
a file or two
sh$ echo [ot]*
or two
sh$ echo n*
n*
And in Bash,
bash$ echo n*
n*
bash$ shopt -s nullglob
bash$ echo n*
I'm guessing you are confused about how the current working directory affects the resolution of directory names; maybe read Difference between ./ and ~/
How to iterate files in directory with for loop in Bash
The for-loop is basically sound. However, if the directory is empty, the loop will be executed once, with the variable file
containing the literal text /var/spool/bandit24/*
.
The stat
message is not from the for
-loop, but from one of the commands in the loop.
The correct way would be to test if the directory is empty before you continue. You could put something like
if [ $(find . -type f | wc -l) -eq 0 ] ; then
echo "Nothing to do"
exit 0
fi
right after the cd
.
Some other comments on your script.
- If you do a
cd
in the script, you don't need to specify the full path anymore. - Your quoting is not really consistent. That may not be a problem if your file names never contain spaces or strange characters, but I would, for example
timeout -s 9 60 "./$file"
andrm -f "./file"
/var/spool/bandit/*
will never contain.
or..
, so that test is useless.- You could also replace the test with
if [ -f "$file" ] ; then
Iterating over file (and directory) names with bash
Use a wild card: for file in *; do …; done
. That keeps the spaces in the names correct. Consider shopt -s nullglob
too. Neither your code nor my suggestion lists names starting with a dot .
.
Also, use if [ -d "$file" ]
with double quotes around the variable value to avoid spacing problems.
Hence:
#!/bin/bash
shopt -s nullglob
files=0
dir=0
for file in *
do
if [ -d "$file" ]
then
dir=$(($dir+1))
else
files=$(($files+1))
fi
done
echo "files=$files, directories=$dir"
In Bash, there are also other ways of writing the arithmetic, such as ((files++))
.
Loop through files in a given directory
If you only want the files non-recursively in the current directory, combine what you have:
read -p 'Enter the directory path: ' directory
for file in "$directory"/*; do
echo "$file"
done
If you want to loop recursively and you have bash 4, it's not much harder:
shopt -s globstar
for file in "$directory"/**/*; do …
But if you only have bash 3, you'd be better off using find
.
find "$directory"
loop over files and extract part of filename
Just re-assign the loop variable at the beginning of each iteration:
for sample in *.vcf; do
sample=${sample%_*}
# do stuff here
done
bash iterate over a directory sorted by file size
You can use a mix of find
(to print file sizes and names), sort
(to sort the output of find
) and cut
(to remove the sizes). In case you have very unusual file names containing any possible character including newlines, it is safer to separate the files by a character that cannot be part of a name: NUL
.
#/bin/bash
if [ -z "$1" ]; then
echo "Please supply the filename suffixes to delete.";
exit;
fi;
filter=$1;
while IFS= read -r -d '' -u 3 FILE; do
clear
cat "$FILE"
printf '\n\n'
rm -i "$FILE"
done 3< <(find . -mindepth 1 -maxdepth 1 -type f -name "*.$filter" \
-printf '%s\t%p\0' | sort -zn | cut -zf 2-)
Note that we must use a different file descriptor than stdin
(3
in this example) to pass the file names to the loop. Else, if we use stdin
, it will also be used to provide the answers to rm -i
.
Related Topics
Rsync, 'Uid/Gid Impossible to Set' Cases Cause Future Hard Link Failure, How to Fix
I'm Having Difficulty Understanding the Shellshock Vulnerability Verification
What Is Segment 00 in My Linux Executable Program (64 Bits)
Linux Script Start,Stop,Restart
Delete the Word Whose Length Is Less Than 2 in Bash
How to Print Current Time in Kernel
Error When Installing Opencv on Ubuntu 14.04
Interacting with Files from Multiple Directories via Bash Script
Using Sed to Print Between Two Patterns
Why Fftw on Windows Is Faster Than on Linux
Docker Overlay2: Error Walking File System: Oserror [Errno 40] Too Many Levels of Symbolic Links
How to Delete Files Over (N) Days Old But Leave (N) Files Regardless of Age
Extracting Variable in Yaml from a Shell Script
Using Scanf into Global or Local Variables (On the Stack), 32-Bit Calling Convention
How to Move First Column to Last Column in Unix
Syntax Error of ";; Unexpected" on Simple Init Script for Debian
Differencebetween These Two Commands Which Are Used to Run Shell Script