Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to perform a for-each loop over all the files under a specified path?

Tags:

linux

bash

shell

The following command attempts to enumerate all *.txt files in the current directory and process them one by one:

for line in "find . -iname '*.txt'"; do       echo $line      ls -l $line;  done 

Why do I get the following error?:

ls: invalid option -- 'e' Try `ls --help' for more information. 
like image 845
0x90 Avatar asked Feb 25 '13 10:02

0x90


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.


2 Answers

Here is a better way to loop over files as it handles spaces and newlines in file names:

#!/bin/bash  find . -type f -iname "*.txt" -print0 | while IFS= read -r -d $'\0' line; do     echo "$line"     ls -l "$line"     done 
like image 112
dogbane Avatar answered Sep 23 '22 00:09

dogbane


The for-loop will iterate over each (space separated) entry on the provided string.

You do not actually execute the find command, but provide it is as string (which gets iterated by the for-loop). Instead of the double quotes use either backticks or $():

for line in $(find . -iname '*.txt'); do       echo "$line"      ls -l "$line" done 

Furthermore, if your file paths/names contains spaces this method fails (since the for-loop iterates over space separated entries). Instead it is better to use the method described in dogbanes answer.


To clarify your error:

As said, for line in "find . -iname '*.txt'"; iterates over all space separated entries, which are:

  • find
  • .
  • -iname
  • '*.txt' (I think...)

The first two do not result in an error (besides the undesired behavior), but the third is problematic as it executes:

ls -l -iname 

A lot of (bash) commands can combine single character options, so -iname is the same as -i -n -a -m -e. And voila: your invalid option -- 'e' error!

like image 24
Veger Avatar answered Sep 24 '22 00:09

Veger