เหตุใดจึงไม่ xargs ในการค้นหาทำงานกับชุดคำสั่งที่ใช้ pushd และ popd เพื่อเดินทรีย่อยไดเรกทอรี


1

บนเครื่อง Linux Centos 4 ฉันพยายามสร้างบรรทัดคำสั่ง bash แบบง่าย ๆ เพื่อเดินโครงสร้างไดเรกทอรีด้านล่างไดเรกทอรีปัจจุบันที่กำหนดเองและในแต่ละไดเรกทอรีย่อยให้แตะที่ไฟล์รายการเนื้อหาของไดเรกทอรี แต่ไปป์/dev/nullและลบไฟล์ที่ถูกสัมผัส จุดที่ไม่ชัดเจนของสคริปต์นี้คือการทำให้ระบบไคลเอ็นต์ / เซิร์ฟเวอร์ NFS ต้นแบบเพื่อให้แน่ใจว่าเนื้อหาของแต่ละไดเรกทอรีสะท้อนการเปลี่ยนแปลงที่เกิดขึ้นกับเครื่องอื่นซึ่งอาจใช้เวลาในการเผยแพร่ ฉันพบวิธีแก้ปัญหานี้เพื่อหลีกเลี่ยงความล่าช้า ละเว้นข้อดีของเหตุผลในการทำเช่นนี้เพราะเหตุใดฉันจึงไม่เสนอสคริปต์ทุบตี

[CentosMachine] find . -type d -print0 | xargs -0 -I {} pushd {}; touch xYzZy.fixZ; ls &> /dev/null; rm -f xYzZy.fixZ; popd
xargs: pushd: No such file or directory
bash: popd: directory stack empty

findคำสั่งเป็นปัจจุบันกลับ:

.
./dir
./emptyDir
./dirOfDir
./dirOfDir/ofDir
./dirOfDir/ofDir/Dir(empty)

ตอนแรกฉันคิดว่าอาจ(และ)ในหนึ่งในชื่อไดเรกทอรีอาจเป็นปัญหา แต่การเปลี่ยนชื่อไดเรกทอรีที่จะ./dirOfDir/ofDir/Dir_empty_ไม่เปลี่ยนอาการ ฉันลองดูstraceผลลัพธ์ แต่ไม่เห็นอะไรที่ช่วย แต่ได้เห็นไดเรกทอรีที่กำลังประมวลผล

นี่เป็นตัวอย่างของการสิ้นสุดของstraceผลลัพธ์ที่มีการเปลี่ยนชื่อไดเรกทอรีให้ใช้เครื่องหมายขีดล่างแทนวงเล็บ:

[...]
chdir("ofDir")                          = 0
lstat64(".", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
lstat64("Dir_empty_", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
open("Dir_empty_", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY) = 4
fstat64(4, {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
fcntl64(4, F_SETFD, FD_CLOEXEC)         = 0
getdents64(4, /* 2 entries */, 32768)   = 48
getdents64(4, /* 0 entries */, 32768)   = 0
close(4)                                = 0
chdir("Dir_empty_")                     = 0
lstat64(".", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
chdir("..")                             = 0
lstat64(".", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
chdir("..")                             = 0
lstat64(".", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
chdir("..")                             = 0
lstat64(".", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
fchdir(3)                               = 0
write(1, ".\0./dir\0./emptyDir\0./dirOfDir\0./"..., 75) = 75
exit_group(0)                      = ?

คำตอบ:


1

xargs เป็นเครื่องมือที่มีประโยชน์มากสำหรับ

  1. ดำเนินการคำสั่งด้วยข้อโต้แย้งที่นำมาจากแหล่งไดนามิกและ
  2. ลดจำนวนการเรียกใช้คำสั่งด้วยการสร้างบรรทัดคำสั่งที่ยาวพร้อมด้วยอาร์กิวเมนต์หลายตัว

เมื่อคุณไม่ได้ทำ # 2 (เช่นการดำเนินการหนึ่งคำสั่งต่ออาร์กิวเมนต์เช่นเดียวกับที่คุณทำ) xargsไม่มีคุณค่ามากนัก มีวิธีอื่นในการเรียกใช้คำสั่ง โดยเฉพาะอย่างยิ่งถ้าแหล่งที่มาของการขัดแย้งคือfindคุณสามารถใช้-execตัวเลือก:

find . -type d -exec bash -c 'pushd "{}" &> /dev/null; touch xYzZy.fixZ; ls &> /dev/null; rm -f xYzZy.fixZ; popd &> /dev/null'

แต่คำตอบนี้เหมือนกับของคุณเรียกใช้กระบวนการเชลล์สำหรับแต่ละไดเรกทอรี และแต่ละกระบวนการมีสภาพแวดล้อมการดำเนินการของตัวเอง การเปลี่ยนไดเร็กทอรีการทำงานในกระบวนการย่อยไม่มีผลกับกระบวนการพาเรนต์ ดังนั้นคุณจึงไม่จำเป็นต้องใช้และpushd popdและคุณไม่จำเป็นต้องระบุbash; ธรรมดาshจะทำ และถ้าคุณยังไม่ได้ตั้งค่าการปรับเปลี่ยนครั้งคุณไม่จำเป็นต้องtouch; คำสั่ง null เปลี่ยนเส้นทางจะสร้างไฟล์ ดังนั้นเราสามารถลดค่าข้างต้นเป็น:

find . -type d -exec sh -c 'cd "{}"; > xYzZy.fixZ; ls &> /dev/null; rm -f xYzZy.fixZ'

สำหรับกรณีการใช้งานของคุณสิ่งนี้อาจไม่สำคัญ แต่ในสถานการณ์อื่นคุณอาจต้องการดำเนินการสามขั้นตอนสุดท้ายต่อเมื่อcdประสบความสำเร็จ:

find . -type d -exec sh -c 'cd "{}" && { > xYzZy.fixZ; ls &> /dev/null; rm -f xYzZy.fixZ;}'

โปรดทราบว่าคุณจะต้องมีช่องว่างหลังและอัฒภาคก่อน{}


1

ฉันพบคำตอบของฉันด้วยคำถามล้นสแต็คนี้ ใส่คำสั่งหลายคำในแบบฟอร์มนี้:

bash -c 'command1; command2; ...'

ซึ่งใช้ที่นี่ให้:

find . -type d -print0 | xargs -0 -I {} bash -c 'pushd "{}"; touch xYzZy.fixZ; ls &> /dev/null; rm -f xYzZy.fixZ; popd'

โปรดสังเกตว่าการเพิ่มเครื่องหมายคำพูดล้อมรอบpushd "{}"เพื่อให้ไดเร็กตอรี่ด้วย(และ)ทำงานอย่างถูกต้อง หากปราศจากข้อผิดพลาดคุณจะได้รับ:

bash: -c: line 0: syntax error near unexpected token `('
bash: -c: line 0: `pushd ./dirOfDir/ofDir/Dir(empty) &> /dev/null; touch xYzZy.fixZ; ls &> /dev/null; rm -f xYzZy.fixZ; popd &> /dev/null'

อย่างไรก็ตาม, pushedและpopdยังต้องการการปราบปรามเพื่อหลีกเลี่ยงเอาต์พุต:

find . -type d -print0 | xargs -0 -I {} bash -c 'pushd "{}" &> /dev/null; touch xYzZy.fixZ; ls &> /dev/null; rm -f xYzZy.fixZ; popd &> /dev/null'

คุณตอบคำถามโดยไม่ตอบคำถาม คำตอบสั้น ๆ คือxargsไม่สามารถใช้คำสั่งผสมได้ คุณต้องล้อมคำสั่งผสมในสตริงและส่งไปยังเชลล์
สกอตต์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.