Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to loop over files in directory and change path and add suffix to filename

I need to write a script that starts my program with different arguments, but I'm new to Bash. I start my program with:

./MyProgram.exe Data/data1.txt [Logs/data1_Log.txt].

Here is the pseudocode for what I want to do:

for each filename in /Data do   for int i = 0, i = 3, i++     ./MyProgram.exe Data/filename.txt Logs/filename_Log{i}.txt   end for end for 

So I'm really puzzled how to create second argument from the first one, so it looks like dataABCD_Log1.txt and start my program.

like image 881
Dobrobobr Avatar asked Dec 27 '13 06:12

Dobrobobr


People also ask

How do you loop through all the files in a directory in bash?

The syntax to loop through each file individually in a loop is: create a variable (f for file, for example). Then define the data set you want the variable to cycle through. In this case, cycle through all files in the current directory using the * wildcard character (the * wildcard matches everything).

How do you loop a directory in Linux?

We use a standard wildcard glob pattern '*' which matches all files. By adding a '/' afterward, we'll match only directories. Then, we assign each directory to the value of a variable dir. In our simple example, we then execute the echo command between do and done to simply output the value of the variable dir.

How do I Cat all files in a directory?

Show activity on this post. You can use the * character to match all the files in your current directory. cat * will display the content of all the files.


2 Answers

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 line
  • basename 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.

like image 141
Gordon Davisson Avatar answered Oct 10 '22 10:10

Gordon Davisson


Sorry for necromancing the thread, but whenever you iterate over files by globbing, it's good practice to avoid the corner case where the glob does not match (which makes the loop variable expand to the (un-matching) glob pattern string itself).

For example:

for filename in Data/*.txt; do     [ -e "$filename" ] || continue     # ... rest of the loop body done 

Reference: Bash Pitfalls

like image 33
Cong Ma Avatar answered Oct 10 '22 12:10

Cong Ma