How to execute a command for each line of a file?

For example, right now I'm using the following to change a couple of files whose Unix paths I wrote to a file:

cat file.txt | while read in; do chmod 755 "$in"; done 

Is there a more elegant, safe way?

+133
bash coding-style loops batch-file line
Dec 18 '12 at 18:17
source share
6 answers

If your file is not too large and all the files are well-named (without spaces or other special characters, such as quotation marks), you can simply:

 chmod 755 $(<file.txt) 

If you have special characters and / or many lines in file.txt .

 xargs -0 chmod 755 < <(tr \\n \\0 <file.txt) 

if your command should be executed exactly 1 time by record:

 xargs -0 -n 1 chmod 755 < <(tr \\n \\0 <file.txt) 

This is not necessary for this example, since chmod accepts multiple files as an argument, but this matches the question header.

In some cases, you can locate the file argument in commands generated with xargs :

 xargs -0 -I '{}' -n 1 myWrapper -arg1 -file='{}' wrapCmd < <(tr \\n \\0 <file.txt) 
+93
Dec 18
source share

Yes.

 while read in; do chmod 755 "$in"; done < file.txt 

This way you can avoid the cat process.

cat almost always bad for such a purpose. You can learn more about Cat Useless Use

+142
Dec 18 '12 at 18:19
source share

if you have a good selector (for example, all .txt files in a directory) you can do:

 for i in *.txt; do chmod 755 "$i"; done 

bash for loop

or your option:

 while read line; do chmod 755 "$line"; done <file.txt 
+14
Dec 18 '12 at 18:31
source share

If you know that there are no spaces at the input:

 xargs chmod 755 < file.txt 

If there can be spaces in the paths, and if you have GNU xargs:

 tr '\n' '\0' < file.txt | xargs -0 chmod 755 
+13
Dec 18 '12 at 18:49
source share

If you want to run your command in parallel for each line, you can use GNU Parallel

 parallel -a <your file> <program> 

Each line of your file will be passed to the program as an argument. By default, parallel starts as many threads as your processor counts. But you can specify it with -j

+10
Mar 21 '16 at 18:02
source share

I see that you noted bash, but Perl would also be a good way to do this:

 perl -p -e '`chmod 755 $_`' file.txt 

You can also apply regular expression to make sure you get the files you need, for example. only process .txt files:

 perl -p -e 'if(/\.txt$/) `chmod 755 $_`' file.txt 

To β€œsee” what happens, simply replace the backreferences with double quotes and add print :

 perl -p -e 'if(/\.txt$/) print "chmod 755 $_"' file.txt 
+2
Dec 18 '12 at 18:49
source share



All Articles