Misalnya, sekarang saya menggunakan yang berikut untuk mengubah beberapa file yang jalur Unix yang saya tulis ke file:
cat file.txt | while read in; do chmod 755 "$in"; done
Apakah ada cara yang lebih elegan, lebih aman?
Ini karena tidak hanya ada 1 jawaban ...
shell
ekspansi baris perintahxargs
alat khususwhile read
dengan beberapa komentarwhile read -u
menggunakan dedicated fd
, untuk pemrosesan interaktif (sampel)Mengenai permintaan OP: berjalan chmod
pada semua target yang tercantum dalam file , xargs
adalah alat yang ditunjukkan. Tetapi untuk beberapa aplikasi lain, sejumlah kecil file, dll ...
Jika file Anda tidak terlalu besar dan semua file diberi nama dengan baik (tanpa spasi atau karakter khusus lain seperti tanda kutip), Anda dapat menggunakan shell
ekspansi baris perintah . Secara sederhana:
chmod 755 $(<file.txt)
Untuk sejumlah kecil file (baris), perintah ini adalah yang lebih ringan.
xargs
adalah alat yang tepatUntuk jumlah file yang lebih besar, atau hampir semua jumlah baris di file input Anda ...
Bagi banyak binutils alat, seperti chown
, chmod
, rm
, cp -t
...
xargs chmod 755 <file.txt
Jika Anda memiliki karakter khusus dan / atau banyak baris file.txt
.
xargs -0 chmod 755 < <(tr \\n \\0 <file.txt)
jika perintah Anda harus dijalankan tepat 1 kali dengan entri:
xargs -0 -n 1 chmod 755 < <(tr \\n \\0 <file.txt)
Ini tidak diperlukan untuk sampel ini, karena chmod
menerima beberapa file sebagai argumen, tetapi ini sesuai dengan judul pertanyaan.
Untuk beberapa kasus khusus, Anda bahkan dapat menentukan lokasi argumen file dalam perintah yang dihasilkan oleh xargs
:
xargs -0 -I '{}' -n 1 myWrapper -arg1 -file='{}' wrapCmd < <(tr \\n \\0 <file.txt)
seq 1 5
sebagai inputCoba ini:
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..
Di mana perintah dilakukan sekali per baris .
while read
dan varian.Seperti yang disarankan OP cat file.txt | while read in; do chmod 755 "$in"; done
akan berfungsi, tetapi ada 2 masalah:
cat |
adalah garpu yang tidak berguna , dan
| while ... ;done
akan menjadi subkulit di mana lingkungan akan menghilang setelahnya ;done
.
Jadi ini bisa ditulis lebih baik:
while read in; do chmod 755 "$in"; done < file.txt
Tapi,
Anda mungkin diperingatkan $IFS
dan read
ditandai:
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...
Dalam beberapa kasus, Anda mungkin perlu menggunakan
while IFS= read -r in;do chmod 755 "$in";done <file.txt
Untuk menghindari masalah dengan nama file stranges. Dan mungkin jika Anda mengalami masalah dengan UTF-8
:
while LANG=C IFS= read -r in ; do chmod 755 "$in";done <file.txt
Saat Anda menggunakan STDIN
untuk membaca file.txt
, skrip Anda tidak dapat interaktif (Anda tidak dapat menggunakan STDIN
lagi).
while read -u
, menggunakan dedicated fd
.Sintaks: while read ...;done <file.txt
akan dialihkan STDIN
ke file.txt
. Itu berarti, Anda tidak akan dapat menangani proses, sampai mereka selesai.
Jika Anda berencana membuat alat interaktif , Anda harus menghindari penggunaan STDIN
dan menggunakan beberapa deskriptor file alternatif .
Deskriptor file Konstanta adalah: 0
untuk STDIN , 1
untuk STDOUT dan 2
untuk STDERR . Anda bisa melihatnya dengan:
ls -l /dev/fd/
atau
ls -l /proc/self/fd/
Dari sana, Anda harus memilih nomor yang tidak digunakan, antara 0
dan 63
(lebih banyak, tergantung pada sysctl
alat superuser) sebagai deskriptor file :
Untuk demo ini, saya akan menggunakan fd 7
:
exec 7<file.txt # Without spaces between `7` and `<`!
ls -l /dev/fd/
Maka Anda bisa menggunakan read -u 7
cara ini:
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
Untuk menutup fd/7
:
exec 7<&- # This will close file descriptor 7.
ls -l /dev/fd/
Nota: Saya membiarkan versi striked karena sintaks ini bisa berguna, ketika melakukan banyak I / O dengan proses paralel:
mkfifo sshfifo
exec 7> >(ssh -t user@host sh >sshfifo)
exec 6<sshfifo
xargs
awalnya dibangun untuk menjawab kebutuhan semacam ini, beberapa fitur, seperti membangun perintah selama mungkin di lingkungan saat ini untuk memohonchmod
dalam kasus ini kurang mungkin, mengurangi garpu memastikan efisiensi.while ;do..done <$file
jalankan 1 garpu untuk 1 file.xargs
dapat menjalankan 1 garpu untuk ribuan file ... dengan cara yang dapat diandalkan.cat file.txt | tr \\n \\0 | xargs -0 -n1 chmod 755
tr \\n \\0 <file.txt |xargs -0 [command]
sekitar 50% lebih cepat dari metode yang Anda gambarkan.Iya.
Dengan cara ini Anda dapat menghindari suatu
cat
proses.cat
hampir selalu buruk untuk tujuan seperti ini. Anda dapat membaca lebih lanjut tentang Penggunaan Cat yang Tidak Berguna.sumber
cat
adalah ide yang baik, tetapi dalam kasus ini, yang perintah yang ditunjukkan adalahxargs
chmod
(yaitu benar-benar menjalankan satu perintah untuk setiap baris dalam file).read -r
membaca satu baris dari input standar (read
tanpa-r
menginterpretasikan backslash, Anda tidak menginginkan itu)."jika Anda memiliki pemilih yang bagus (misalnya semua file .txt dalam direktori) yang dapat Anda lakukan:
bash untuk loop
atau varian Anda:
sumber
Jika Anda tahu Anda tidak memiliki spasi kosong di input:
Jika mungkin ada spasi putih di jalur, dan jika Anda memiliki GNU xargs:
sumber
xargs
kuat. Alat ini sangat tua dan kodenya sangat ditinjau kembali . Tujuannya semula adalah untuk membangun garis sehubungan dengan batasan shell (64kchar / line atau semacamnya). Sekarang alat ini dapat bekerja dengan file yang sangat besar dan dapat mengurangi banyak jumlah garpu ke perintah akhir. Lihat jawaban saya dan / atauman xargs
.brew install findutils
), dan kemudian memanggil GNU xargs dengangxargs
sebaliknya, misalnyagxargs chmod 755 < file.txt
Jika Anda ingin menjalankan perintah secara paralel untuk setiap baris, Anda dapat menggunakan GNU Parallel
Setiap baris file Anda akan diteruskan ke program sebagai argumen. Secara default
parallel
berjalan sebanyak thread yang dihitung CPU Anda. Tapi Anda bisa menentukannya dengan-j
sumber
Saya melihat bahwa Anda menandai bash, tetapi Perl juga merupakan cara yang baik untuk melakukan ini:
Anda juga bisa menerapkan regex untuk memastikan Anda mendapatkan file yang tepat, misalnya hanya memproses file .txt:
Untuk "melihat" apa yang terjadi, cukup ganti backtick dengan tanda kutip ganda dan tambahkan
print
:sumber
chmod
fungsiperl -lpe 'chmod 0755, $_' file.txt
- gunakan-l
untuk fitur "auto-chomp"Anda juga dapat menggunakan AWK yang dapat memberi Anda lebih banyak fleksibilitas untuk menangani file
jika file Anda memiliki pemisah bidang seperti:
Untuk mendapatkan hanya bidang pertama yang Anda lakukan
Anda dapat memeriksa detail lebih lanjut tentang Dokumentasi GNU https://www.gnu.org/software/gawk/manual/html_node/Very-Simple.html#Very-Simple
sumber
Logikanya berlaku untuk banyak tujuan lain. Dan bagaimana cara membaca .sh_history setiap pengguna dari / home / filesystem? Bagaimana jika jumlahnya ribuan?
Ini adalah skrip https://github.com/imvieira/SysAdmin_DevOps_Scripts/blob/master/get_and_run.sh
sumber
Aku tahu ini sudah terlambat tapi tetap saja
Jika kebetulan Anda lari ke file teks yang disimpan dengan windows
\r\n
bukan\n
, Anda mungkin bingung dengan output jika perintah Anda telah sth setelah membaca baris sebagai argumen. Jadi jangan hapus\r
, misalnya:sumber