มีใครบ้างที่มีแม่แบบเชลล์สคริปต์สำหรับทำบางสิ่งบางอย่างls
สำหรับรายการชื่อไดเรกทอรีและวนซ้ำแต่ละรายการและทำบางสิ่งบางอย่างหรือไม่
ฉันวางแผนที่จะทำls -1d */
เพื่อรับรายชื่อไดเรกทอรี
มีใครบ้างที่มีแม่แบบเชลล์สคริปต์สำหรับทำบางสิ่งบางอย่างls
สำหรับรายการชื่อไดเรกทอรีและวนซ้ำแต่ละรายการและทำบางสิ่งบางอย่างหรือไม่
ฉันวางแผนที่จะทำls -1d */
เพื่อรับรายชื่อไดเรกทอรี
คำตอบ:
แก้ไขไม่ให้ใช้ ls โดยที่ glob จะทำอย่างไรตามที่ @ shawn-j-goff และคนอื่น ๆ แนะนำ
เพียงใช้for..do..done
ลูป:
for f in *; do
echo "File -> $f"
done
คุณสามารถแทนที่*
ด้วย*.txt
หรือ glob อื่น ๆ ที่ส่งกลับรายการ (ของไฟล์ไดเรกทอรีหรือสิ่งใด ๆ สำหรับเรื่องนั้น) คำสั่งที่สร้างรายการเช่น$(cat filelist.txt)
หรือแทนที่จริงด้วยรายการ
ภายในdo
ลูปคุณเพียงอ้างถึงตัวแปรลูปที่มีคำนำหน้าเครื่องหมายดอลลาร์ (ดังนั้น$f
ในตัวอย่างด้านบน) คุณสามารถecho
ทำได้หรือทำสิ่งอื่นที่คุณต้องการ
ตัวอย่างเช่นหากต้องการเปลี่ยนชื่อ.xml
ไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันเป็น.txt
:
for x in *.xml; do
t=$(echo $x | sed 's/\.xml$/.txt/');
mv $x $t && echo "moved $x -> $t"
done
หรือดียิ่งขึ้นถ้าคุณใช้ Bash คุณสามารถใช้การขยายพารามิเตอร์ Bash แทนการวางไข่ subshell:
for x in *.xml; do
t=${x%.xml}.txt
mv $x $t && echo "moved $x -> $t"
done
for
ls
@ DanielA ขาวคุณอาจพิจารณาที่จะยอมรับคำตอบนี้ถ้ามันไม่เป็นประโยชน์ (หรืออาจทำให้เข้าใจผิด) เนื่องจากอย่างที่คุณพูดคุณกำลังทำหน้าที่ในไดเรกทอรี คำตอบของ Shawn J. Goff ควรให้วิธีการแก้ปัญหาที่มีประสิทธิภาพและทำงานได้ดีขึ้น
ls
เอาท์พุท , คุณไม่ควรอ่านเอาท์พุทในfor
ห่วงคุณควรใช้$()
แทน `` และใช้คำพูดมากขึ้น™ ฉันแน่ใจว่า @CoverosGene มีความหมายดี แต่นี่แย่มาก
ls
ls -1 | while read line; do stuff; done
อย่างน้อยก็ไม่มีทางทำลายช่องว่างได้
mv -v
คุณไม่จำเป็นต้องใช้echo "moved $x -> $t"
โดยใช้การส่งออกของls
ที่จะได้รับชื่อไฟล์ที่เป็นความคิดที่ไม่ดี มันสามารถนำไปสู่การชำรุดหรือแม้แต่สคริปต์อันตราย นี่เป็นเพราะชื่อไฟล์สามารถมีตัวละครใด ๆ ยกเว้น/
และnull
ตัวอักษรและls
ไม่ได้ใช้ตัวละครอย่างใดอย่างหนึ่งเป็นตัวคั่นดังนั้นถ้าชื่อไฟล์มีช่องว่างหรือขึ้นบรรทัดใหม่คุณจะได้รับผลลัพธ์ที่ไม่คาดคิด
มีสองวิธีที่ดีมากในการวนซ้ำไฟล์ ที่นี่ฉันใช้echo
เพื่อแสดงให้เห็นถึงการทำอะไรกับชื่อไฟล์ คุณสามารถใช้อะไรก็ได้
อย่างแรกคือการใช้คุณสมบัติการหมุนรอบตัวของเชลล์
for dir in */; do
echo "$dir"
done
เชลล์ขยายออก*/
เป็นอาร์กิวเมนต์แยกต่างหากที่for
ลูปอ่าน แม้ว่าจะมีช่องว่างขึ้นบรรทัดใหม่หรืออักขระแปลก ๆ อื่น ๆ ในชื่อไฟล์for
จะเห็นชื่อที่สมบูรณ์แต่ละชื่อเป็นหน่วยอะตอม ไม่ได้แยกวิเคราะห์รายการ แต่อย่างใด
ถ้าคุณต้องการเรียกซ้ำไปยังไดเรกทอรีย่อยการทำเช่นนี้จะไม่เกิดขึ้นถ้าเชลล์ของคุณมีคุณสมบัติการขยายแบบบางอย่าง (เช่นbash
's globstar
หากเชลล์ของคุณไม่มีคุณสมบัติเหล่านี้หรือหากคุณต้องการให้แน่ใจว่าสคริปต์ของคุณจะทำงาน find
บนความหลากหลายของระบบแล้วตัวเลือกต่อไปคือการใช้
find . -type d -exec echo '{}' \;
ที่นี่find
คำสั่งจะเรียกecho
และส่งผ่านอาร์กิวเมนต์ของชื่อไฟล์ มันทำสิ่งนี้เพียงครั้งเดียวสำหรับแต่ละไฟล์ที่พบ เช่นเดียวกับตัวอย่างก่อนหน้านี้ไม่มีการแยกรายการชื่อไฟล์ แทนชื่อไฟล์จะถูกส่งอย่างสมบูรณ์เป็นข้อโต้แย้ง
ไวยากรณ์ของ-exec
ข้อโต้แย้งดูตลกเล็กน้อย find
รับอาร์กิวเมนต์แรกหลังจาก-exec
และถือว่าเป็นโปรแกรมที่จะเรียกใช้และทุกอาร์กิวเมนต์ที่ตามมาจะใช้เป็นอาร์กิวเมนต์เพื่อส่งผ่านไปยังโปรแกรมนั้น มีข้อโต้แย้งพิเศษสองข้อที่-exec
ต้องดู คนแรกคือ{}
; อาร์กิวเมนต์นี้ถูกแทนที่ด้วยชื่อไฟล์ที่ส่วนก่อนหน้าของการfind
สร้าง สิ่งที่สองคือ;
สิ่งที่ทำให้เราfind
รู้ว่านี่คือจุดสิ้นสุดของรายการอาร์กิวเมนต์ที่ส่งผ่านไปยังโปรแกรม find
ต้องการสิ่งนี้เพราะคุณสามารถดำเนินการต่อกับอาร์กิวเมนต์ที่มีไว้สำหรับfind
และไม่ได้มีไว้สำหรับโปรแกรม exec เหตุผลสำหรับการ\
นี้ก็คือเชลล์ก็ปฏิบัติต่อเช่นกัน;
พิเศษ - มันแสดงให้เห็นถึงจุดสิ้นสุดของคำสั่งดังนั้นเราจำเป็นต้องหลบหนีเพื่อให้เปลือกให้มันเป็นอาร์กิวเมนต์find
มากกว่าที่จะใช้มันสำหรับตัวเอง; อีกวิธีหนึ่งในการทำให้เชลล์ไม่ปฏิบัติกับมันเป็นพิเศษคือใส่ไว้ในเครื่องหมายคำพูด: ';'
ใช้ได้ทั้ง\;
เพื่อจุดประสงค์นี้
find
ฉันหวังว่าผู้คนมากขึ้นจะใช้ มีเวทย์มนตร์ที่สามารถทำได้และแม้แต่ข้อ จำกัด การรับรู้ของ-exec
สามารถแก้ไขได้ ตัวเลือกยังเป็นที่มีคุณค่าสำหรับการใช้งานกับ-print0
xargs
สำหรับไฟล์ที่มีช่องว่างในคุณจะต้องตรวจสอบให้แน่ใจว่าได้อ้างอิงตัวแปรดังนี้:
for i in $(ls); do echo "$i"; done;
หรือคุณสามารถเปลี่ยนตัวแปรสภาพแวดล้อม input field separator (IFS):
IFS=$'\n';for file in $(ls); do echo $i; done
ในที่สุดขึ้นอยู่กับสิ่งที่คุณทำคุณอาจไม่จำเป็นต้อง ls:
for i in *; do echo "$i"; done;
\n
ไม่เพียงพอ ls
มันไม่เป็นความคิดที่ดีที่จะแนะนำให้แยกการส่งออกของ
หากคุณติดตั้งGNU Parallel http://www.gnu.org/software/parallel/คุณสามารถทำสิ่งนี้ได้:
ls | parallel echo {} is in this dir
ในการเปลี่ยนชื่อ. txt ทั้งหมดเป็น. xml:
ls *.txt | parallel mv {} {.}.xml
ดูวิดีโอแนะนำสำหรับ GNU Parallel เพื่อเรียนรู้เพิ่มเติม: http://www.youtube.com/watch?v=OpaiGYxkSuQ
เพียงเพิ่มคำตอบของ CoverosGene นี่คือวิธีในการแสดงรายการชื่อไดเรกทอรีเท่านั้น:
for f in */; do
echo "Directory -> $f"
done
ทำไมไม่ตั้งค่า IFS ให้เป็นบรรทัดใหม่แล้วจับเอาท์พุทของls
อาร์เรย์ การตั้งค่า IFS เป็นบรรทัดใหม่ควรแก้ไขปัญหาเกี่ยวกับตัวละครตลกในชื่อไฟล์ การใช้งานls
สามารถทำได้ดีเพราะมีระบบอำนวยความสะดวกในการจัดเรียง
(ในการทดสอบฉันมีปัญหาในการตั้งค่า IFS \n
แต่ตั้งค่าเป็น newline backspace ทำงานตามที่แนะนำที่นี่)
เช่น (สมมติว่าls
รูปแบบการค้นหาที่ต้องการส่งผ่าน$1
):
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
FILES=($(/bin/ls "$1"))
for AFILE in ${FILES[@]}
do
... do something with a file ...
done
IFS=$SAVEIFS
นี้จะมีประโยชน์โดยเฉพาะอย่างยิ่งใน OS X เช่นจะจับรายชื่อของไฟล์เรียงตามวันที่สร้าง (ที่เก่าแก่ที่สุดไปหาใหม่) ซึ่งเป็นคำสั่งls
ls -t -U -r
\n
ไม่เพียงพอ การแก้ปัญหาที่ถูกต้องเพียงใช้สำหรับห่วงกับการขยายตัวชื่อพา ธ find
หรือ
นี่คือวิธีที่ฉันทำ แต่อาจมีวิธีที่มีประสิทธิภาพมากกว่า
ls > filelist.txt
while read filename; do echo filename: "$filename"; done < filelist.txt
ls | while read i; do echo filename: $i; done