ในฐานะที่เป็นความคิดเห็น Goldilocks' และการอ้างอิงของมนุษยชาติอธิบาย
shift
reassigns พารามิเตอร์ตำแหน่ง ( $1
, $2
ฯลฯ ) เพื่อที่$1
จะใช้เวลาอยู่กับค่าเก่า$2
,
$2
ใช้เวลากับค่าของ$3
ฯลฯ*
ค่าเก่า$1
จะถูกยกเลิก ( $0
ไม่เปลี่ยนแปลง) เหตุผลบางประการในการทำเช่นนี้ ได้แก่ :
- มันช่วยให้คุณเข้าถึงอาร์กิวเมนต์ที่สิบ (ถ้ามี) ได้ง่ายขึ้น
$10
ไม่ทำงาน - ถูกตีความว่า$1
ต่อกันกับ0
(และอาจสร้างบางอย่างเช่นHello0
) หลังจากอาร์กิวเมนต์สิบกลายเป็นshift
$9
(อย่างไรก็ตามในเชลล์ที่ทันสมัยที่สุดคุณสามารถใช้${10}
)
- เมื่อBash Guide for Beginnersแสดงให้เห็นแล้วก็สามารถใช้ในการวนรอบข้อโต้แย้งได้ IMNSHO นี่คือเงอะงะ;
for
ดีกว่ามากสำหรับสิ่งนั้น
- เช่นเดียวกับในสคริปต์ตัวอย่างของคุณมันทำให้ง่ายต่อการประมวลผลข้อโต้แย้งทั้งหมดด้วยวิธีเดียวกันยกเว้นบางอย่าง ตัวอย่างเช่นในสคริปต์ของคุณ
$1
และ$2
เป็นสตริงข้อความในขณะที่$3
และพารามิเตอร์อื่น ๆ ทั้งหมดเป็นชื่อไฟล์
ดังนั้นนี่คือวิธีการเล่น สมมติว่าสคริปต์ของคุณถูกเรียกใช้Patryk_script
และถูกเรียกว่าเป็น
Patryk_script USSR Russia Treaty1 Atlas2 Pravda3
สคริปต์เห็น
$1 = USSR
$2 = Russia
$3 = Treaty1
$4 = Atlas2
$5 = Pravda3
คำสั่งostr="$1"
กำหนดตัวแปรเพื่อostr
คำสั่งUSSR
แรกshift
เปลี่ยนพารามิเตอร์ตำแหน่งดังนี้:
$1 = Russia
$2 = Treaty1
$3 = Atlas2
$4 = Pravda3
คำสั่งnstr="$1"
กำหนดตัวแปรเพื่อnstr
คำสั่งRussia
ที่สองshift
เปลี่ยนพารามิเตอร์ตำแหน่งดังนี้:
$1 = Treaty1
$2 = Atlas2
$3 = Pravda3
และแล้วfor
การเปลี่ยนแปลงห่วงUSSR
( $ostr
) ไปRussia
( $nstr
) ในไฟล์Treaty1
, และAtlas2
Pravda3
สคริปต์มีปัญหาเล็กน้อย
สำหรับไฟล์ใน $ @; ทำ
หากสคริปต์ถูกเรียกใช้เป็น
Patryk_script สหภาพโซเวียตรัสเซีย Treaty1 "World Atlas2" Pravda3
มันเห็น
$ 1 = ล้าหลัง
$ 2 = รัสเซีย
$ 3 = Treaty1
$ 4 = World Atlas2
$ 5 = Pravda3
แต่เพราะ$@
ไม่ได้ยกพื้นที่ในWorld Atlas2
ไม่ได้ยกมาและfor
ห่วงคิดว่ามันมีสี่ไฟล์: Treaty1
, World
, และAtlas2
Pravda3
ควรจะเป็นอย่างนี้
สำหรับไฟล์ใน "$ @"; ทำ
(เพื่ออ้างอิงอักขระพิเศษใด ๆ ในอาร์กิวเมนต์) หรือเพียงแค่
สำหรับไฟล์ทำ
(ซึ่งเทียบเท่ากับเวอร์ชันที่ยาวกว่า)
eval "sed 's /" $ ostr "/" $ nstr "/ g' $ file"
ไม่จำเป็นต้องมีสิ่งนี้เพื่อให้เป็นeval
และการผ่านการป้อนข้อมูลของผู้ใช้ที่ไม่ถูกตรวจสอบไปยังeval
อาจเป็นอันตรายได้ ตัวอย่างเช่นหากสคริปต์ถูกเรียกเป็น
Patryk_script "'; rm *;'" สนธิสัญญารัสเซีย 1 Atlas2 Pravda3
มันจะดำเนินการrm *
! นี่เป็นเรื่องที่น่ากังวลอย่างมากหากสคริปต์สามารถเรียกใช้ด้วยสิทธิ์ที่สูงกว่าของผู้ใช้ที่เรียกใช้งาน เช่นหากสามารถเรียกใช้ผ่านsudo
หรือเรียกใช้จากเว็บอินเตอร์เฟส อาจไม่สำคัญหากคุณใช้เป็นตัวคุณเองในไดเรกทอรีของคุณ แต่มันสามารถเปลี่ยนเป็น
sed "s / $ ostr / $ nstr / g" "$ file"
สิ่งนี้ยังคงมีความเสี่ยงอยู่บ้าง แต่ก็มีความรุนแรงน้อยกว่ามาก
if [ -f $file ]
, > $file.tmp
และmv $file.tmp $file
ควรจะเป็นif [ -f "$file" ]
, > "$file.tmp"
และmv "$file.tmp" "$file"
ตามลำดับในการจัดการชื่อไฟล์ที่อาจมีช่องว่าง (หรือตัวตลกและอื่น ๆ ) ในพวกเขา ( eval "sed …
คำสั่งยัง mangles ชื่อไฟล์ที่มีช่องว่างอยู่ด้วย)
* shift
รับอาร์กิวเมนต์ตัวเลือก: จำนวนเต็มบวกที่ระบุจำนวนพารามิเตอร์ที่ต้องการเลื่อน ค่าเริ่มต้นคือหนึ่ง ( 1
) ยกตัวอย่างเช่นshift 4
เป็นสาเหตุ$5
ที่จะกลายเป็น$1
,
$6
ที่จะกลายเป็น$2
และอื่น ๆ (โปรดทราบว่าตัวอย่างในคู่มือ Bash สำหรับผู้เริ่มต้นผิด) และเพื่อให้สคริปต์ของคุณสามารถแก้ไขได้
ostr="$1"
nstr="$2"
shift 2
ซึ่งอาจถือว่ามีความชัดเจนมากขึ้น
หมายเหตุท้าย / คำเตือน:
ภาษาพร้อมรับคำสั่งของ Windows (ไฟล์แบทช์) ยังรองรับSHIFT
คำสั่งซึ่งโดยพื้นฐานแล้วเป็นสิ่งเดียวกับshift
คำสั่งใน Unix shells โดยมีความแตกต่างที่โดดเด่นหนึ่งประการซึ่งฉันจะซ่อนเพื่อพยายามป้องกันไม่ให้ผู้อื่นสับสน:
- คำสั่งเช่น
SHIFT 4
นั้นเป็นข้อผิดพลาดทำให้เกิดข้อผิดพลาด“ พารามิเตอร์ไม่ถูกต้องกับคำสั่ง SHIFT”
SHIFT /n
ที่n
เป็นจำนวนเต็มระหว่าง 0 และ 8 ที่ถูกต้อง - แต่มันไม่ได้เปลี่ยนครั้ง มันเลื่อนหนึ่งครั้งโดยเริ่มจาก อาร์กิวเมนต์ที่n ดังนั้น ทำให้(อาร์กิวเมนต์ที่ห้า) กลายเป็นและอื่น ๆ โดยปล่อยให้อาร์กิวเมนต์ 0 ถึง 3 เพียงอย่างเดียวn
SHIFT /4
%5
%4,
%6
%5
pushd
และpopd
)