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 ~/
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"
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
Loop over files in a directory not working
I assume that you expect to loop through all files within the directory you pass. To do that, you need to change your loop:
for file in "$1"/*
It's worth mentioning that for
doesn't have any built-in behaviour to enumerate items in a directory, it simply iterates over the list of words that you pass it. The *
, expanded by the shell, is what results in the loop iterating over a list of files.
Your condition would need modifying too, as the *
needs to be outside of quotes (and the rest doesn't need to be inside them, either):
if [[ $f = *.txt ]]
But you can avoid the need for the conditional by directly looping through all files ending in .txt
:
for file in "$1"/*.txt
You may also want to consider the case where there are no matches, in which case I guess you expect the loop not to run. One way to do that in bash would be:
# failing glob expands to nothing, rather than itself
shopt -s nullglob
for file in "$1"/*.txt
# ...
done
# unset this behaviour if you don't want it in the rest of the script
shopt -u nullglob
Expect: How to iterate over files in a directory?
You would write:
#!/usr/bin/env expect
foreach f [glob /path/*.csv] {
puts $f
}
Expect is an extension of Tcl. In addition to the expect
man page, a link to the Tcl command documentation will be helpful: https://www.tcl.tk/man/tcl8.6/TclCmd/contents.htm
Iterate Over Files in Variable Path (Bash)
Glob expansion doesn't happen inside quotes (both single and double) in shell.
You should be using this code:
for file in "$path"/*; do
echo "INFO - Checking $file"
[[ -e $file ]] || continue
done
Related Topics
Tty_Flip_Buffer_Push() Sends Data Back to Itself
Flags in Objdump Output of Object File
Configure Options for Building Mingw-64 on Linux-64 for Linux-64 (Ultimately Targetting Windows-64)
Write to a File After Piping Output from Tail -F Through to Grep
How to Join a Thread in Linux Kernel
Provide Password Using Shell Script
Accessing Files Outside the Document Root with Apache
Mono Take Mscorlib.Dll 2.0 Instead of 4.0
Use Sed to Delete Certain Lines Using an Index with the Line Numbers to Delete
Run Multiple Commands At Once in the Same Terminal
Clear Screen in a Linux Terminal Using Assembly
How Do Programs Communicate with Each Other
Sudoers Nopasswd: Sudo: No Tty Present and No Askpass Program Specified
How to Make Static Linked Elf File to Load Ld_Preload .So
In Linux, Schedule Task to Hour, Minute, Second Precision
Difference Between Kernel, Kernel-Thread and User-Thread