Saya telah mencoba menemukan jawaban untuk pertanyaan ini untuk sementara waktu. Saya menulis skrip cepat untuk menjalankan perintah berdasarkan output dari awk.
ID_minimum=1000
for f in /etc/passwd;
do
awk -F: -vID=$ID_minimum '$3>=1000 && $1!="nfsnobody" { print "xfs_quota -x -c 'limit bsoft=5g bhard=6g $1' /home "}' $f;
done
Masalahnya adalah bahwa -c
argumen mengambil perintah dalam tanda kutip tunggal dan saya tidak tahu bagaimana cara menghindarinya dan juga yang $1
tidak berkembang menjadi nama pengguna.
Pada dasarnya saya hanya mencoba untuk menghasilkan:
xfs_quota -x -c 'limit bsoft=5g bhard=6g userone' /home
xfs_quota -x -c 'limit bsoft=5g bhard=6g usertwo' /home
dll ...
awk
Jawaban:
Untuk menjalankan perintah
xfs_quota -x -c 'limit bsoft=5g bhard=6g USER' /home
untuk masingUSER
- masing yang memiliki UID setidaknya$ID_minimum
, pertimbangkan untuk menguraikan pengguna tersebut terlebih dahulu dan kemudian benar - benar menjalankan perintah, daripada mencoba membuat string yang mewakili perintah yang ingin Anda jalankan.Jika Anda membuat string perintah, Anda harus melakukannya
eval
. Ini salah dan mudah salah. Lebih baik hanya mendapatkan daftar nama pengguna dan kemudian menjalankan perintah.Perhatikan bahwa tidak ada kebutuhan aktual untuk kutipan tunggal di sekitar argumen setelahnya
-c
. Di sini saya menggunakan tanda kutip ganda karena saya ingin shell untuk memperluas$user
variabel yang berisi nilai yang diekstraksi olehawk
.Saya menggunakan
${ID_minimum:-1000}
saat memberikan nilai kemin
variabel dalamawk
perintah. Ini akan diperluas ke nilai$ID_minimum
, atau1000
jika variabel itu kosong atau tidak disetel.Jika Anda benar - benar ingin, Anda bisa membuat loop di atas mencetak perintah alih-alih menjalankannya:
Perhatikan lagi bahwa menggunakan tanda kutip ganda dalam string perintah yang dihasilkan (bukan tanda kutip tunggal) tidak akan membingungkan shell dengan cara apa pun jika Anda menjalankan perintah yang dihasilkan menggunakan
eval
atau melalui beberapa cara lain. Jika itu mengganggu Anda, cukup tukarkan tanda kutip tunggal dan ganda di argumen pertama keprintf
atas.sumber
getent
(tetap pada desktop), dan pertanyaannya tidak ditandai "linux."/home
tidak benar-benar digunakan pada macOS (itu ada di sana, tetapi biasanya kosong).Ini agak konyol karena benar-benar tidak ada loop dengan hanya satu nilai.
Tetapi masalah ini sepertinya mencetak satu tanda kutip dari awk. Anda bisa melarikan diri dari shell, tetapi Anda juga bisa menggunakan backslash-eskt dalam awk untuk mencetaknya. adalah karakter dengan nilai numerik OOO (dalam oktal ), begitu juga . Jadi ini akan menjadi salah satu cara untuk melakukannya:
\OOO
\047
'
Anda bisa menggunakan pelarian yang sama di hex,
\x27
tetapi bisa salah ditafsirkan dalam beberapa implementasi jika karakter berikut ini adalah digit heksadesimal yang valid. (Dan tentu saja saya mengasumsikan ASCII atau set karakter yang kompatibel ASCII, misalnya UTF-8.)sumber
l
bukan merupakan digit hex, tetapi"\x27df\n"
akan diperlakukan seperti"\x27" "df"
pada busybox awk atau mawk tetapi sebagai"\xdf"
(0x27df
cast ke 8 bit char) dalam awk dan gawk asli (itulah alasan mengapa POSIX tidak menentukan\xHH
). Oktal (\047
) tidak memiliki masalah yang sama dan POSIX. Bagaimanapun, itu mengasumsikan sistem ASCII (asumsi yang masuk akal belakangan ini).Gunakan
-f -
opsi untuk awk untuk mengambil skrip dari stdin dan dokumen di sini:sumber
Ini berhasil.
sumber
'\''
atau'"'"'
. Keduanya bekerja, keduanya terlihat menjengkelkan.Ini tubuh yang mengerikan, tapi cepat dan mudah ...
sumber
Bagi saya ini merupakan peluang ideal untuk mempekerjakan Anda
xargs
(atau GNU Parallel ):Keuntungan menggunakan
xargs
atauparallel
adalah Anda dapat menghapus perintahecho
saat Anda siap menjalankan perintah nyata (mungkin menggantinya dengansudo
, jika perlu).Anda juga dapat menggunakan opsi utilitas
-p
/--interactive
(yang terakhir ini hanya untuk GNU) atau--dry-run
(parallel
hanya), untuk mendapatkan konfirmasi sebelum menjalankan masing-masing, atau hanya untuk melihat apa yang akan berjalan, sebelum Anda menjalankannya.Metode umum yang digunakan di atas harus berfungsi pada sebagian besar Unix, dan tidak memerlukan
xargs
opsi khusus GNU . Kutipan ganda memang perlu "diloloskan" sehingga muncul secara harfiah di output. Perhatikan bahwa "string pengganti,"{}
, dixargs -I{}
dapat berupa apa pun yang Anda inginkan, dan-I
menyiratkan-L1
(jalankan satu perintah per baris input daripada mengelompokkannya).GNU Paralel tidak memerlukan
-I
option ({}
adalah string pengganti default), dan memberi Anda bonus instan menjalankan banyak pekerjaan secara paralel, bahkan jika Anda tidak ingin repot-repot belajar tentang apa saja dari yang lain fitur .Sebagai catatan, aku bahkan tidak yakin apakah
xfs_quota
's-c
opsi seharusnya digunakan seperti ini, meskipun saya tidak memiliki XFS filesystem berguna untuk tes. Anda mungkin tidak perlu berurusan dengan string yang dikutip di tempat pertama (kecuali jika Anda mengharapkan nama pengguna dengan spasi putih di dalamnya, yang saya kira mungkin), karena sepertinya Anda dapat memberikan beberapa-c
opsi pada baris perintah yang sama, menurut ke halaman manual disertakan denganxfsprogs
4.5.something.sumber
Dengan GNU Parallel Anda dapat melakukan:
Penjelasan:
--colsep :
Berpisah:-q
jangan pisahkan perintah pada spasi (pertahankan '...' sebagai string tunggal).{=1 ... =}
Evaluasi ekspresi perl ini pada argumen pertama baris.$_ eq "nfsnobody" and skip();
Jika nilai == nfsnobody: skip$arg[3] <= 1000 and skip();
If argument3 <= 1000: skipsumber