Câu trả lời:
Điều này là do không chỉ có 1 câu trả lời ...
shell
mở rộng dòng lệnhxargs
công cụ chuyên dụngwhile read
với một số nhận xétwhile read -u
sử dụng chuyên dụng fd
, để xử lý tương tác (mẫu)Về yêu cầu OP: chạy chmod
trên tất cả các mục tiêu được liệt kê trong tệp , xargs
là công cụ được chỉ định. Nhưng đối với một số ứng dụng khác, số lượng tệp nhỏ, v.v ...
Nếu tệp của bạn không quá lớn và tất cả các tệp đều được đặt tên tốt (không có dấu cách hoặc ký tự đặc biệt khác như dấu ngoặc kép), bạn có thể sử dụng shell
mở rộng dòng lệnh . Đơn giản:
chmod 755 $(<file.txt)
Đối với số lượng nhỏ tệp (dòng), lệnh này là nhẹ hơn.
xargs
là công cụ phù hợpĐối với số lượng tệp lớn hơn hoặc gần như bất kỳ số lượng dòng nào trong tệp đầu vào của bạn ...
Đối với nhiều binutils công cụ, như chown
, chmod
, rm
, cp -t
...
xargs chmod 755 <file.txt
Nếu bạn có ký tự đặc biệt và / hoặc rất nhiều dòng trong file.txt
.
xargs -0 chmod 755 < <(tr \\n \\0 <file.txt)
nếu lệnh của bạn cần được chạy chính xác 1 lần bằng cách nhập:
xargs -0 -n 1 chmod 755 < <(tr \\n \\0 <file.txt)
Điều này là không cần thiết cho mẫu này, vì chmod
chấp nhận nhiều tệp làm đối số, nhưng điều này phù hợp với tiêu đề của câu hỏi.
Đối với một số trường hợp đặc biệt, bạn thậm chí có thể xác định vị trí của đối số tệp trong các lệnh được tạo bởi xargs
:
xargs -0 -I '{}' -n 1 myWrapper -arg1 -file='{}' wrapCmd < <(tr \\n \\0 <file.txt)
seq 1 5
đầu vàoThử cái này:
xargs -n 1 -I{} echo Blah {} blabla {}.. < <(seq 1 5)
Blah 1 blabla 1..
Blah 2 blabla 2..
Blah 3 blabla 3..
Blah 4 blabla 4..
Blah 5 blabla 5..
Trường hợp Commande được thực hiện một lần trên mỗi dòng .
while read
và các biến thể.Theo đề xuất của OP cat file.txt | while read in; do chmod 755 "$in"; done
sẽ hoạt động, nhưng có 2 vấn đề:
cat |
là một ngã ba vô dụng , và
| while ... ;done
sẽ trở thành một subshell nơi môi trường sẽ biến mất sau đó ;done
.
Vì vậy, điều này có thể được viết tốt hơn:
while read in; do chmod 755 "$in"; done < file.txt
Nhưng,
Bạn có thể được cảnh báo $IFS
và read
cờ:
help read
read: read [-r] ... [-d delim] ... [name ...] ... Reads a single line from the standard input... The line is split into fields as with word splitting, and the first word is assigned to the first NAME, the second word to the second NAME, and so on... Only the characters found in $IFS are recognized as word delimiters. ... Options: ... -d delim continue until the first character of DELIM is read, rather than newline ... -r do not allow backslashes to escape any characters ... Exit Status: The return code is zero, unless end-of-file is encountered...
Trong một số trường hợp, bạn có thể cần phải sử dụng
while IFS= read -r in;do chmod 755 "$in";done <file.txt
Để tránh các vấn đề với tên tập tin lạ. Và có thể nếu bạn gặp sự cố với UTF-8
:
while LANG=C IFS= read -r in ; do chmod 755 "$in";done <file.txt
Trong khi bạn sử dụng STDIN
để đọc file.txt
, tập lệnh của bạn không thể tương tác (bạn không thể sử dụng STDIN
nữa).
while read -u
, sử dụng chuyên dụng fd
.Cú pháp: while read ...;done <file.txt
sẽ chuyển hướng STDIN
đến file.txt
. Điều đó có nghĩa là, bạn sẽ không thể xử lý quá trình cho đến khi họ hoàn thành.
Nếu bạn có kế hoạch tạo công cụ tương tác , bạn phải tránh sử dụng STDIN
và sử dụng một số mô tả tệp thay thế .
Các mô tả tệp hằng là: 0
cho STDIN , 1
cho STDOUT và 2
cho STDERR . Bạn có thể thấy chúng bằng cách:
ls -l /dev/fd/
hoặc là
ls -l /proc/self/fd/
Từ đó, bạn phải chọn số chưa sử dụng, giữa 0
và 63
(trên thực tế, tùy thuộc vào sysctl
công cụ siêu người dùng) làm mô tả tệp :
Đối với bản demo này, tôi sẽ sử dụng fd 7
:
exec 7<file.txt # Without spaces between `7` and `<`!
ls -l /dev/fd/
Sau đó, bạn có thể sử dụng read -u 7
cách này:
while read -u 7 filename;do
ans=;while [ -z "$ans" ];do
read -p "Process file '$filename' (y/n)? " -sn1 foo
[ "$foo" ]&& [ -z "${foo/[yn]}" ]&& ans=$foo || echo '??'
done
if [ "$ans" = "y" ] ;then
echo Yes
echo "Processing '$filename'."
else
echo No
fi
done 7<file.txt
done
Để đóng fd/7
:
exec 7<&- # This will close file descriptor 7.
ls -l /dev/fd/
Nota: Tôi để striked phiên bản vì cú pháp này có thể là hữu ích, khi làm nhiều I / O với sự tương đồng xử lý:
mkfifo sshfifo
exec 7> >(ssh -t user@host sh >sshfifo)
exec 6<sshfifo
cat file.txt | tr \\n \\0 | xargs -0 -n1 chmod 755
tr \\n \\0 <file.txt |xargs -0 [command]
nhanh hơn khoảng 50% so với phương pháp bạn mô tả.
Đúng.
while read in; do chmod 755 "$in"; done < file.txt
Bằng cách này bạn có thể tránh được một cat
quá trình.
cat
hầu như luôn luôn xấu cho một mục đích như thế này. Bạn có thể đọc thêm về Sử dụng Mèo vô dụng.
cat
là một ý tưởng tốt, nhưng trong trường hợp này, các lệnh chỉ định làxargs
chmod
(tức là thực sự chạy một lệnh cho mỗi dòng trong tệp).
read -r
đọc một dòng duy nhất từ đầu vào tiêu chuẩn ( read
không có -r
dấu gạch chéo ngược, bạn không muốn điều đó)."
nếu bạn có một bộ chọn đẹp (ví dụ: tất cả các tệp .txt trong một thư mục) bạn có thể làm:
for i in *.txt; do chmod 755 "$i"; done
hoặc một biến thể của bạn:
while read line; do chmod 755 "$line"; done <file.txt
Nếu bạn biết bạn không có bất kỳ khoảng trắng nào trong đầu vào:
xargs chmod 755 < file.txt
Nếu có thể có khoảng trắng trong các đường dẫn và nếu bạn có GNU xargs:
tr '\n' '\0' < file.txt | xargs -0 chmod 755
xargs
là mạnh mẽ. Công cụ này rất cũ và mã của anh ấy được xem xét lại mạnh mẽ . Mục tiêu của anh là khởi đầu để xây dựng các dòng liên quan đến các giới hạn về vỏ (64kchar / dòng hoặc một cái gì đó như vậy). Bây giờ công cụ này có thể làm việc với các tệp rất lớn và có thể giảm rất nhiều số ngã ba đến lệnh cuối cùng. Xem câu trả lời của tôi và / hoặc man xargs
.
brew install findutils
), và sau đó invoke xargs GNU với gxargs
thay vào đó, ví dụgxargs chmod 755 < file.txt
Nếu bạn muốn chạy lệnh song song cho mỗi dòng, bạn có thể sử dụng GNU Parallel
parallel -a <your file> <program>
Mỗi dòng tệp của bạn sẽ được chuyển đến chương trình dưới dạng đối số. Theo mặc định, parallel
chạy nhiều chủ đề như số lượng CPU của bạn. Nhưng bạn có thể chỉ định nó với-j
Tôi thấy rằng bạn đã gắn thẻ bash, nhưng Perl cũng sẽ là một cách tốt để làm điều này:
perl -p -e '`chmod 755 $_`' file.txt
Bạn cũng có thể áp dụng biểu thức chính quy để đảm bảo bạn nhận được đúng tệp, ví dụ: chỉ xử lý tệp .txt:
perl -p -e 'if(/\.txt$/) `chmod 755 $_`' file.txt
Để "xem trước" những gì đang xảy ra, chỉ cần thay thế backticks bằng dấu ngoặc kép và trả trước print
:
perl -p -e 'if(/\.txt$/) print "chmod 755 $_"' file.txt
chmod
chức năng
perl -lpe 'chmod 0755, $_' file.txt
- sử dụng -l
cho tính năng "tự động nhai"
Bạn cũng có thể sử dụng AWK để có thể linh hoạt hơn để xử lý tệp
awk '{ print "chmod 755 "$0"" | "/bin/sh"}' file.txt
nếu tệp của bạn có dấu phân cách trường như:
trường1, trường2, trường3
Để chỉ nhận được lĩnh vực đầu tiên bạn làm
awk -F, '{ print "chmod 755 "$1"" | "/bin/sh"}' file.txt
Bạn có thể kiểm tra thêm chi tiết về Tài liệu GNU https://www.gnu.org/software/gawk/manual/html_node/Very-Simple.html#Very-Simple
Logic áp dụng cho nhiều mục tiêu khác. Và làm thế nào để đọc .sh_history của mỗi người dùng từ / home / filesystem? Nếu có hàng ngàn người thì sao?
#!/bin/ksh
last |head -10|awk '{print $1}'|
while IFS= read -r line
do
su - "$line" -c 'tail .sh_history'
done
Đây là kịch bản https://github.com/imvieira/SysAdmin_DevOps_Scripts/blob/master/get_and_run.sh
xargs
đã được xây dựng ban đầu để đáp ứng nhu cầu này, một số tính năng, như lệnh xây dựng càng lâu càng tốt trong môi trường hiện tại để gọichmod
trong trường hợp này càng ít càng tốt, giảm dĩa đảm bảo hiệu quả.while ;do..done <$file
implie chạy 1 fork cho 1 file.xargs
có thể chạy 1 ngã ba cho hàng ngàn tệp ... một cách đáng tin cậy.