ชื่อไฟล์ 'find -exec' pass มีช่องว่างอย่างไร


14

หากฉันมีไดเรกทอรีที่มีไฟล์บางไฟล์ที่ชื่อมีช่องว่างเช่น

$ ls -1 dir1
file 1
file 2
file 3

ฉันสามารถคัดลอกทั้งหมดไปยังไดเรกทอรีอื่นเช่นนี้ได้สำเร็จ:

$ find dir1 -mindepth 1 -exec cp -t dir2 {} +

อย่างไรก็ตามการส่งออกของfind dir1 -mindepth 1มีช่องว่างที่ไม่หนี:

$ find dir1 mindepth 1
dir1/file 1
dir1/file 3
dir1/file 3

หากฉันใช้print0แทนprintเอาต์พุตยังคงมีช่องว่างที่ไม่ได้ใช้ Escape:

$ find dir1 mindepth 1 -print0
dir1/file 1dir1/file 2dir1/file 3

หากต้องการคัดลอกไฟล์เหล่านี้ด้วยตนเองโดยใช้cpฉันจะต้องหลีกเลี่ยงช่องว่าง แต่ดูเหมือนว่าสิ่งนี้ไม่จำเป็นเมื่อcpมีการบอกกล่าวมาfindโดยไม่คำนึงว่าฉันจะใช้+หรือ\;ท้ายคำสั่ง

อะไรคือเหตุผลนี้

คำตอบ:


8

findคำสั่งรันคำสั่งโดยตรง คำสั่งรวมถึงอาร์กิวเมนต์ชื่อไฟล์จะไม่ถูกประมวลผลโดยเชลล์หรือสิ่งอื่นใดที่อาจแก้ไขชื่อไฟล์ มันปลอดภัยมาก

คุณถูกต้องว่าไม่มีความจำเป็นที่จะหลบหนีชื่อไฟล์ซึ่งเป็นตัวแทนจาก{}บนfindบรรทัดคำสั่ง

findส่งชื่อไฟล์ดิบจากดิสก์โดยตรงไปยังรายการอาร์กิวเมนต์ภายในของ-execคำสั่งในกรณีของคุณcpคำสั่ง


1
สั้น, find..execสามารถจัดการกับชื่อไฟล์แปลกในตัวเอง ..
heemayl

2
กฎข้อแรกของ linux club คือคุณไม่ต้องแยกคำสั่ง ls
Sergiy Kolodyazhnyy

5

คำถามคือสองส่วน:

  • วิธีการที่จะ findจัดการกับโปรแกรมโทรใช้-execโดยไม่ต้องทำงานเป็นปัญหาที่มีช่องว่างที่ฝังอยู่ในชื่อไฟล์และ
  • -print0ตัวเลือกที่ดีคืออะไร?

สำหรับครั้งแรกที่findจะทำให้การเรียกระบบจริงหนึ่งในกลุ่มของสายที่เกี่ยวข้องเรียกว่า"exec" มันส่งผ่านชื่อไฟล์เป็นอาร์กิวเมนต์โดยตรงไปยังการโทรนี้ซึ่งจะถูกส่งโดยตรง (หลังจากสร้างกระบวนการใหม่) โดยไม่สูญเสียข้อมูลเกี่ยวกับชื่อไฟล์

findคุณลักษณะPOSIX มีการ+อธิบายดังนี้ในเหตุผล :

คุณสมบัติของfindยูทิลิตี้ของ SVR4 คือ-exec+ ยกเลิกของอุปกรณ์หลัก นี้ชื่อไฟล์ที่ได้รับอนุญาตให้มีอักขระพิเศษ (โดยเฉพาะอย่างยิ่งการขึ้นบรรทัดใหม่ตัวอักษร) xargsที่จะรวมกลุ่มกันได้โดยไม่มีปัญหาที่เกิดขึ้นได้ถ้าชื่อไฟล์ดังกล่าวจะประปา การใช้งานอื่น ๆ ได้เพิ่มวิธีอื่น ๆ ในการแก้ไขปัญหานี้โดยเฉพาะอย่างยิ่ง-print0หลักที่เขียนชื่อไฟล์ด้วย null byte terminator นี่ถือว่าเป็นที่นี่ แต่ไม่ได้นำมาใช้ การใช้ null terminator หมายความว่ายูทิลิตีใด ๆ ที่กำลังจะประมวล-print0ผลเอาต์พุตของ find ต้องเพิ่มตัวเลือกใหม่เพื่อแยกตัวสิ้นสุด null ที่ตอนนี้กำลังอ่านอยู่

ว่า " สะดุดตา-print0หลัก" หมายถึง GNU findและxargsซึ่งการแก้ปัญหาในทางที่แตกต่างกัน นอกจากนี้ยังได้รับการสนับสนุนโดย FreeBSD และfind xargsหากคุณเพิ่ม-0ตัวเลือก (ดูหน้าคู่มือ ) ในการxargsโทรโปรแกรมนั้นจะยอมรับบรรทัดที่ยกเลิกด้วยอักขระ "null byte" ในทางกลับกันxargsเรียกexec -functions ที่จะทำมันทำงาน ความแตกต่างหลักระหว่าง-print0และ-0คุณลักษณะกับ+คุณลักษณะคืออดีตผ่านชื่อไฟล์ผ่านไปป์ในขณะที่หลังไม่ได้ นักพัฒนาค้นหาการใช้งานเกือบทุกฟีเจอร์ ท่อจะไม่มีข้อยกเว้น

กลับไปตัวอย่างเช่น OP ซึ่งใช้-tตัวเลือกในการcp: ที่ไม่พบในPOSIX CP แต่ก็เป็นส่วนขยาย (aka "คุณสมบัติที่ไม่เป็นมาตรฐาน") ให้โดยGNU CP การ-0ขยายตัวของxargsจะไม่ปรับปรุงตัวอย่างนี้ แต่มีกรณีอื่น ๆ ที่สามารถใช้อย่างมีประสิทธิภาพ - โปรดจำไว้ว่ามีทางเลือกแบบพกพา+ซึ่ง GNU findยอมรับ


-1

( นี่ควรเป็นความคิดเห็น แต่มันใหญ่เกินไป )

สำหรับผู้ที่ต้องการลองสิ่งต่างๆ:

list_positional_parameters.shสร้างสคริปต์รายการพารามิเตอร์ตำแหน่งผ่านในที่เรียกว่า

#!/bin/bash

# http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_09_07.html
# Try globbing patterns, e.g. "X[[:digit:]][[:digit:]]" to see what happens

if [ $# -lt 1 ]; then
   echo "Usage: $0 and then at least one parameter"
   exit 1
fi

counter=1

while (($#)); do
   echo "$counter = '$1'"
   # pop positional argument 1 off the stack of positional arguments
   shift
   (( counter++ ))
done

ทำงานfindกับมันในบางไดเรกทอรี $ dir:

find "$dir" -exec ./list_positional_parameters.sh '{}' ';' | less

ตามที่คาดไว้มีเพียงพารามิเตอร์เดียวในการโทรทั้งหมดชื่อไฟล์ไม่ว่าจะมีช่องว่างในชื่อหรือไม่


1
นอกจากนี้คุณยังอาจจะใช้printfเหมือนprintf '"%s"\n' "$@"จะพิมพ์ออกมาทั้งหมดอาร์กิวเมนต์ตำแหน่งที่ยกมาสำหรับการตรวจสอบภาพ
Kusalananda
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.