ทำไม -a ใน“ #! / bin / sh -a” ส่งผลกระทบต่อ sed และ“ set -a” ไม่?


20

ถ้าฉันเรียกใช้ไฟล์. sh ต่อไปนี้:

#!/bin/sh -a
echo "a" | sed -e 's/[\d001-\d008]//g'

ผลลัพธ์เป็นข้อผิดพลาด:

sed: -e นิพจน์ # 1, อักขระ 18: ช่วงสิ้นสุดไม่ถูกต้อง

แต่ถ้าฉันเรียกใช้ไฟล์. sh ต่อไปนี้:

#!/bin/sh
set -a
echo "a" | sed -e 's/[\d001-\d008]//g'

มันทำงานโดยไม่มีข้อผิดพลาด รหัสที่สองไม่ควรจะเทียบเท่ากับรหัสแรก? ทำไมข้อผิดพลาดในอันแรก?


ไม่shเหมือนกันทั้งหมด ไม่ว่าทั้งหมดจะเทียบเท่า ซึ่งshที่คุณใช้? ระบบปฏิบัติการใด? และอันไหน (อาจจะ? sed --versionถ้ามันไม่ล้มเหลว)
ไอแซค

1
การตั้งค่าLC_COLLATE=C(หรือPOSIX) สำหรับการโทรเพื่อsedแก้ไขปัญหา
Jeff Schaller

4
ข้อแตกต่างที่ฉันพบ: สคริปต์ตัวแรกเรียกใช้ sed (และสันนิษฐานยูทิลิตี้อื่น ๆ ) ด้วยPOSIXLY_CORRECT=yในสภาพแวดล้อมที่สองไม่มีPOSIXLY_CORRECTในสภาพแวดล้อม เชลล์ที่ฉันเรียกใช้สคริปต์ทั้งสองไม่มีPOSIXLY_CORRECTในสภาพแวดล้อม
Mark Plotnick

1
อ๊ะecho "a" | POSIXLY_CORRECT=y sed -e 's/[\d001-\d008]//g' ทำซ้ำปัญหาของคุณ
ไอแซค

1
การยืนยันว่าข้างต้นล้มเหลวสำหรับฉันอย่างที่ OP ได้แสดงบน CentOS 7.x - GNU ทุบตีรุ่น 4.2.46 (2) - ปล่อย (x86_64-redhat-linux-gnu) และ CentOS Linux ออก 7.5.1804 (Core) .
slm

คำตอบ:


31

เมื่อ bash ถูกเรียกด้วยชื่อshมันจะทำสิ่งนี้ :

if (shell_name[0] == 's' && shell_name[1] == 'h' && shell_name[2] == '\0')
    act_like_sh++;

จากนั้นตั้งค่าPOSIXLY_CORRECTตัวแปรของเชลล์เป็นy :

if (act_like_sh)
  {
    bind_variable ("POSIXLY_CORRECT", "y", 0);
    sv_strict_posix ("POSIXLY_CORRECT");
  }

bind_variableโทรbind_variable_internalซึ่งหากแอตทริบิวต์เปลือกaคือในเวลา (ซึ่งมันจะเป็นถ้าคุณเรียกเปลือกด้วย-a) เครื่องหมายเปลือกเป็นตัวแปรที่ส่งออก

ดังนั้นในสคริปต์แรกของคุณ:

#!/bin/sh -a
echo "a" | sed -e 's/[\d001-\d008]//g'

sedถูกเรียกด้วยPOSIXLY_CORRECT=yในสภาพแวดล้อมของ บริษัท [\d001-\d008]ซึ่งจะทำให้มันบ่นเกี่ยวกับ (สิ่งเดียวกันจะเกิดขึ้นหากมี--posixตัวเลือก)

ใน GNU sed, เป็นรหัสหลบหนีสำหรับตัวอักษรที่มีค่าตัวเลขในฐาน-10 มมมมแต่ในโหมด POSIX นี้เป็นคนพิการภายในแสดงออกวงเล็บจึงหมายถึงตัวอักษรตัวอักษร, ฯลฯ กับช่วงมาจากไปยัง ตามลำดับของรหัสตัวอักษรมาก่อน(และช่วงจะรวมตัวเลขทั้งหมดยกเว้นศูนย์รวมทั้งตัวอักษรตัวพิมพ์ใหญ่ทั้งหมดรวมทั้งอักขระพิเศษบางตัว) อย่างไรก็ตามในภาษาที่คุณใช้เรียงลำดับก่อนหน้าดังนั้นช่วงนั้นไม่ถูกต้อง\dNNN[\d001-\d008]\d1\1\en_US.UTF-8\1

ในสคริปต์ที่สองของคุณ:

#!/bin/sh
set -a
echo "a" | sed -e 's/[\d001-\d008]//g'

แม้ว่าPOSIXLY_CORRECTจะตั้งค่าไว้ในเชลล์ แต่ก็ไม่ได้ถูกส่งออกดังนั้น sed จึงถูกเรียกใช้โดยไม่POSIXLY_CORRECTอยู่ในสภาพแวดล้อมและทำงานโดยใช้ส่วนขยาย GNU

หากคุณเพิ่มexport POSIXLY_CORRECTใกล้ด้านบนสุดของสคริปต์ที่สองของคุณคุณจะเห็นว่าบ่น


6
สำหรับฉันนั่นเป็นข้อผิดพลาด
Stéphane Chazelas

1
หนังสยองขวัญศักดิ์สิทธิ์ศักดิ์สิทธิ์ Batman! นั่นเป็นมุมแหลมที่น่าสนใจ (และบิตของการเปลี่ยนแปลงที่จะเห็นปัญหาที่มาจาก/bin/shจริงถูกทุบตี) เช่นเดียวกับที่เกิดขึ้นถ้าPOSIXLY_CORRECTอยู่ในสภาพแวดล้อมก่อนที่จะทุบตีเริ่มต้นมันก็จะผ่านมันเป็นsh POSIXLY_CORRECT=y
ilkkachu

3
@StevenPenny แต่POSIXLY_CORRECT ไม่ได้อยู่ในสภาพแวดล้อมเมื่อเชลล์เริ่มทำงานและสคริปต์ไม่ได้ตั้งค่า เปลือกทำอย่างไร มันสร้างตัวแปรสภาพแวดล้อมที่ไม่มีที่ไหนเลยซึ่งไม่ดีเป็นพิเศษเพราะมันทำในโหมดที่ควรจะเป็นและพยายามที่จะเป็นไปตามมาตรฐาน
ilkkachu

4
FWIW, Bash ดูเหมือนจะไม่มีเอกสารว่ามันจะตั้งค่าPOSIXLY_CORRECTด้วยตัวเอง ไม่มีการพูดถึงมันในรายการเอฟเฟกต์ของโหมด POSIXและคำอธิบายตัวแปรบอกเพียงว่าการตั้งค่าให้มันเปลี่ยนเชลล์เป็นโหมด POSIX ไม่ใช่วิธีอื่น ๆ
ilkkachu

1
@ilkkachu เสร็จสิ้น ผมคิดว่าข้อมูลจำเพาะ POSIX allexportนอกจากนี้ยังควรมีการปรับปรุงเพื่อชี้แจงสิ่งที่ตัวแปรรับผลกระทบจาก
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.