ฉันจะใช้อักขระตัวแทนลักษณะ ms-dos กับ ls และ mv ได้อย่างไร


9

ฉันมีความโชคร้ายที่มาจากพื้นหลังของ MS-DOS - แต่อย่างน้อยก็ทำให้ฉันซาบซึ้งว่า Linux มีประสิทธิภาพมากขึ้นเพียงใด ฉันกำลังพยายามทำให้ Linux-Fu ของฉันใกล้เคียงกัน แต่มีสองสิ่งที่สามารถทำได้กับ DOS ซึ่งฉันไม่แน่ใจว่าจะทำอย่างไรให้สำเร็จได้อย่างง่ายดายด้วย Linux:

การเปลี่ยนชื่อไฟล์หลาย ๆ ไฟล์ - การใช้สัญลักษณ์สองตัว

c:\> dir

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt

c:\>rename *.txt *.bak

c:\> dir

Directory of c:\
    file1.bak
    file2.bak
    file3.bak
    file4.bak

ฉันรู้ว่าฉันสามารถใช้find -execที่นี่ แต่มันเป็นไปได้ที่จะใช้ไวยากรณ์ที่สั้นกว่า - บางทีอาจจะmvมีการตั้งค่าสถานะพิเศษหรือไวยากรณ์บางอย่าง? ฉันเดาว่ากุญแจตัวนี้คือwildcard ตัวที่สอง *เนื่องจาก linux ไม่ควรมีปัญหากับอันแรก (เช่นฉันรู้วิธีเลือกไฟล์ที่ฉันต้องการเปลี่ยนชื่อโดยใช้ wildcard)

การเปลี่ยนชื่อไฟล์เดียว - ใช้สัญลักษณ์ตัวแทนเดียว

c:\> dir

Directory of c:\
    file1.txt

c:\>rename file1.txt *.bak

c:\> dir

Directory of c:\
    file1.bak

สิ่งนี้จะเป็นประโยชน์อย่างยิ่งเมื่อเปลี่ยนชื่อไฟล์ที่ยาวและไม่สะดวก ฉันคิดว่าบางทีฉันสามารถใช้mv file1.txt $1.bakท้ายfile1.txt.bakซึ่งก็จะยอมรับได้ แต่ฉันไม่แน่ใจว่าคุณสามารถอ้างอิง$1พารามิเตอร์ inline ด้วยคำสั่งเชลล์ อีกครั้งในกรณีพิเศษนี้เป็นเพียงความสะดวกของวิธี ms-dos bastardizes *wildcard ที่จะใช้เป็นประเภทจับภาพ / แทนที่ตรงกับส่วนหนึ่งของชื่อไฟล์

การกรองรายชื่อไดเรกทอรีด้วย Wildcard

c:\> dir

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt
    text.txt
    \temp       (directory) 

c:\> dir file*

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt

c:\> t*

Directory of c:\
    text.txt
    \temp       (directory) 

ฉันไม่แน่ใจว่าไวยากรณ์ที่ถูกต้องสำหรับการทำเช่นนั้นlsคืออะไรหรือถ้าเป็นไปได้ ถ้าผมทำอะไรเหมือนls t*มันจะ recurse tลงในไดเรกทอรีที่เริ่มต้นด้วย วิธีแก้ปัญหาของฉันมีการใช้find . --max-depth 1 -iname "t*"หรือสิ่งที่ต้องการls -al | grep t- ไม่สั้นและง่ายเท่าที่dir t*ควร

ในที่สุดฉันก็รู้ว่าฉันสามารถตั้งชื่อแทนเพื่อทำให้คำสั่งยาวเหล่านี้สั้นลง แต่ฉันอยากจะเรียนรู้ลินุกซ์แบบนอกกรอบสำหรับทำสิ่งเหล่านี้เพราะบางครั้งคุณเชื่อมต่อกับระบบรีโมตหรือทำงาน บนเครื่องใหม่

ดังนั้นฉันmvและlsไฟล์แบบเดียวกับที่ฉันเคยใช้dirและrenameไฟล์ได้อย่างไร

คำตอบ:


15

หนึ่งในความแตกต่างพื้นฐานระหว่าง Windows cmdและ POSIX shells คือผู้ที่รับผิดชอบในการขยายสัญลักษณ์แทน เชลล์ทำการขยายทั้งหมดที่จำเป็นก่อนที่จะเริ่มคำสั่งจริงที่คุณขอ cmd ส่วนใหญ่ส่งรูปแบบไวด์การ์ดไปยังคำสั่งที่ไม่ได้แก้ไข (ฉันบอกว่าส่วนใหญ่เนื่องจากฉันคิดว่ามีข้อยกเว้นและตัวแปรสภาพแวดล้อมจะขยายตัวในสถานการณ์ส่วนใหญ่) นี่ทำให้การเขียนrenameที่จะทำงานกับไวยากรณ์เดียวกับที่cmdค่อนข้างยุ่งยาก

แต่มีrenameLinux สำหรับ - ด้วยอาร์กิวเมนต์ที่แตกต่างกันอย่างสมบูรณ์ตรวจสอบหน้าคน (ซึ่งเป็นบิตสั้น ๆ ในระบบของฉันและrenameมาจากutil-linuxแพคเกจในระบบของฉันซึ่งควรจะใช้ได้อย่างกว้างขวาง) การเปลี่ยนชื่อครั้งแรกของคุณจะเป็นเช่นนี้:

rename .txt .bak *.txt

โปรดทราบว่าเชลล์ทำการ*ขยายดังนั้นrenameตัวจริงคิดว่ามันถูกเรียกเช่นนี้:

rename .txt .bak file1.txt file2.txt file3.txt ...

ดังนั้นคุณสามารถเดาเวอร์ชันไฟล์เดียวได้:

rename .txt .bak file1.txt

หากคุณไม่ต้องการใช้renameแต่นำไปใช้เองคุณสามารถสร้างฟังก์ชันสำหรับสิ่งนั้นได้ สมมติว่าคุณต้องการเปลี่ยนนามสกุลไฟล์และเปลี่ยนชื่อไฟล์เพียงไฟล์เดียวดูที่:

$ function chext() {
  newext="$1"
  file="$2"
  newfile="${file%.*}$newext"
  echo mv "$file" "$newfile"
}
$ chext .csv test.txt
mv text.txt text.csv

$newfileถูกสร้างโดยใช้การลบสตริงย่อยเพื่อตัดส่วนขยายเดิมออกจากนั้นเชื่อมต่อส่วนขยายใหม่ คุณสามารถขยายฟังก์ชั่นนั้นเพื่อจัดการไฟล์หลาย ๆ ไฟล์ได้อย่างง่ายดาย


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

การสาธิต:

$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:29 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.csv
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

เปลี่ยนชื่อสัญลักษณ์แทน

$ rename .csv .txt f*
$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:34 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.txt
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

เปลี่ยนชื่อไฟล์เดียว

$ rename .txt .csv f1.txt 
$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:34 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.txt
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

ค่าเริ่มต้น ls

$ ls -l t*
-rw-r--r-- 1 owner users    0 Jan  7 17:27 test.csv

test:
total 0
-rw-r--r-- 1 owner users 0 Jan  7 17:33 dont_show_me_please

ls ที่ไม่ตรวจสอบไดเรกทอรี

$ ls -ld t*
drwxr-xr-x 2 owner users 4096 Jan  7 17:33 test
-rw-r--r-- 1 owner users    0 Jan  7 17:27 test.csv

ดีมาก! ฉันคิดว่าฉันเพิ่งขยับเข็มขัดด้วย linux-fu ของฉัน! ขอบคุณ!
cwd

เคล็ดลับเพื่อความคืบหน้าเล็กน้อยกับสิ่งนี้ (และหลีกเลี่ยงหลุมพราง): ใช้ฟังก์ชั่นหรือสคริปต์ง่าย ๆ เพื่อดูว่าเกิดอะไรขึ้นเมื่อคุณทำsomefunc *.Extถ้ารูปแบบนั้นไม่ตรงกับไฟล์ใด ๆ และเล่นกับ quoting เพื่อดูว่าคุณจัดการ โดยไม่ต้องมีการขยาย) ระหว่างฟังก์ชั่น เคล็ดลับความปลอดภัย: ไม่ได้ใช้งานrmได้ทุกที่ในขณะที่การทดลองกับ globbing / การขยายตัวของเปลือก :-)
จ้า

4

สิ่งหนึ่งที่ควรคำนึงถึงเมื่อใช้สัญลักษณ์แทนคือพวกมันขยายโดยเชลล์ แอปพลิเคชันไม่ทราบว่าคุณใช้อักขระตัวแทนหรือพิมพ์ชื่อออกมา ตัวอย่างเช่นถ้าคุณพิมพ์rename *.txt *.bakแล้วคำสั่งเห็นอะไรบางอย่างเช่นrename rename file1.txt file2.txt existingfile.bakข้อมูลไม่เพียงพอที่จะดำเนินการต่อไป

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

echo t*

หากคุณต้องการข้อมูลเพิ่มเติมเกี่ยวกับไฟล์ให้ส่ง-dตัวเลือกไปที่lsเพื่อบอกไม่ให้แสดงรายการเนื้อหาของไดเรกทอรี

ls -ld t*

ไม่มียูทิลิตี้มาตรฐานสำหรับการเปลี่ยนชื่อไฟล์เพราะระบบ unix แรกไม่ได้มาพร้อมกับหนึ่ง วิธีการพกพาเพื่อเปลี่ยนชื่อไฟล์ใช้การวนซ้ำและค่อนข้างละเอียด:

for x in *.txt; do mv -- "$x" "${x%.txt}.bak"; done

มียูทิลิตี้ทั่วไปหลายตัวในการเปลี่ยนชื่อไฟล์ซึ่งไม่มีการรับประกันใด ๆ ที่จะติดตั้งบนระบบยูนิกซ์ที่ให้มา แต่ทั้งหมดนั้นง่ายต่อการติดตั้ง นี่คือคนหลัก:

  • renameจากutil-linuxชุดพร้อมใช้งานบนทุกระบบ Linux ที่ไม่ได้ฝังตัว (และไม่มีที่อื่น) ใน Debian และสัญญาซื้อขายล่วงหน้า (รวมทั้ง Ubuntu) rename.ulคำสั่งนี้จะเรียกว่า หากไม่มีการเกิดขึ้น.txtนอกเหนือจากนามสกุลสุดท้ายคุณสามารถเขียนได้

    rename .txt .bak *.txt
    
  • renameเป็นสคริปต์ Perl ที่ Debian /usr/bin/renameและอนุพันธ์จัดส่งเป็น คุณสามารถเปลี่ยนชื่อไฟล์ตามคำสั่ง Perl โดยพลการ

    rename 's/\.txt\z/\.bak/' *.txt
    
  • mmvซึ่งสามารถเปลี่ยนชื่อคัดลอกและเชื่อมโยงไฟล์ตามรูปแบบหลายชื่อและมีตัวเลือกมากมายที่เกี่ยวข้องกับสิ่งที่เกิดขึ้นหากมีชื่อเป้าหมายอยู่แล้ว โปรดทราบว่าคุณต้องใช้เครื่องหมายคำพูดเพื่อป้องกันการใช้สัญลักษณ์แทนจากส่วนขยายของเชลล์

    mmv '*.txt' '#1.txt'
    
  • zmvเป็นฟังก์ชั่นzshใช้ได้ถ้าหากเชลล์ของคุณคือ zsh มันสามารถจับคู่รูปแบบ zsh โดยพลการ (เพื่อให้คุณสามารถจับคู่ชื่อไฟล์ตามการแสดงออกปกติโดยพลการไม่ได้เป็นเพียงสัญลักษณ์เสริมและคุณสามารถจับคู่ไฟล์ตามเกณฑ์อื่น ๆ เช่นวันที่และขนาด) zmvยังสามารถคัดลอกและลิงค์

    zmv '(*).txt' '$1.txt'
    

หากคุณมีการควบคุมเครื่องจักรที่คุณใช้คำแนะนำของฉันคือการใช้ zsh เป็นเชลล์ของคุณ (มีประโยชน์อื่น ๆ มากกว่าทุบตี) และวางบรรทัดเหล่านี้ใน~/.zshrc:

autoload -U zmv
alias zmv='noglob zmv -w'
alias zcp='zmv -C'
alias zln='zmv -L'
alias zsy='zmv -Ls'

noglobเป็นคุณลักษณะ zsh ที่บอกว่าเชลล์ไม่ให้ขยาย wildcards ในอาร์กิวเมนต์ของคำสั่ง วิธีนี้คุณสามารถเขียนได้zmv *.txt \$1.txt(คุณจะต้องป้องกัน$ในข้อความที่เปลี่ยนทดแทนเสมอ)

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