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, safer way?
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, safer way?
If your file is not too big and all files are well named (without spaces or other special chars like quotes), you could simply:
chmod 755 $(<file.txt)
If you have special chars and/or a lot of lines in file.txt
.
xargs -0 chmod 755 < <(tr \\n \\0 <file.txt)
if your command need to be run exactly 1 time by entry:
xargs -0 -n 1 chmod 755 < <(tr \\n \\0 <file.txt)
This is not needed for this sample, as chmod
accept multiple files as argument, but this match the title of question.
For some special case, you could even define location of file argument in commands generateds by xargs
:
xargs -0 -I '{}' -n 1 myWrapper -arg1 -file='{}' wrapCmd < <(tr \\n \\0 <file.txt)
Yes.
while read in; do chmod 755 "$in"; done < file.txt
This way you can avoid a cat
process.
cat
is almost always bad for a purpose such as this. You can read more about Useless Use of Cat.
If you know you don't have any whitespace in the input:
xargs chmod 755 < file.txt
If there might be whitespace in the paths, and if you have GNU xargs:
tr '\n' '\0' < file.txt | xargs -0 chmod 755
if you have a nice selector (for example all .txt files in a dir) you could do:
for i in *.txt; do chmod 755 "$i"; done
bash for loop
or a variant of yours:
while read line; do chmod 755 "$line"; done <file.txt
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 program as an argument. By default parallel
runs as many threads as your CPUs count. But you can specify it with -j
I see that you tagged bash, but Perl would also be a good way to do this:
perl -p -e '`chmod 755 $_`' file.txt
You could also apply a regex to make sure you're getting the right files, e.g. to only process .txt files:
perl -p -e 'if(/\.txt$/) `chmod 755 $_`' file.txt
To "preview" what's happening, just replace the backticks with double quotes and prepend print
:
perl -p -e 'if(/\.txt$/) print "chmod 755 $_"' file.txt
You can also use AWK which can give you more flexibility to handle the file
awk '{ print "chmod 755 "$0"" | "/bin/sh"}' file.txt
if your file has a field separator like:
field1,field2,field3
To get only the first field you do
awk -F, '{ print "chmod 755 "$1"" | "/bin/sh"}' file.txt
You can check more details on GNU Documentation https://www.gnu.org/software/gawk/manual/html_node/Very-Simple.html#Very-Simple
The logic applies to many other objectives. And how to read .sh_history of each user from /home/ filesystem? What if there are thousand of them?
#!/bin/ksh
last |head -10|awk '{print $1}'|
while IFS= read -r line
do
su - "$line" -c 'tail .sh_history'
done
Here is the script https://github.com/imvieira/SysAdmin_DevOps_Scripts/blob/master/get_and_run.sh