ไวยากรณ์ของเรื่องไม่เท่ากันหรือไม่


22

เมื่อทำการเขียนสคริปต์ฉันมักจะเขียน ifs ของฉันด้วยไวยากรณ์ต่อไปนี้เพราะฉันเข้าใจได้ง่ายขึ้นว่าสิ่งต่อไปนี้ไม่เป็นความจริง

if [ ! "$1" = "$2" ]; then

บางคนบอกว่าวิธีการด้านล่างดีกว่า

if [ "$1" != "$2" ]; then

สิ่งนี้คือเมื่อฉันถามว่าทำไมและมีความแตกต่างกันหรือไม่ไม่มีใครดูเหมือนจะมีคำตอบใด ๆ

ดังนั้นมีความแตกต่างระหว่างสองไวยากรณ์หรือไม่ หนึ่งในนั้นปลอดภัยกว่าหรือไม่ หรือมันเป็นเพียงเรื่องของการตั้งค่า / นิสัย?


9
ในกรณีแรกที่คุณต้องรู้ว่าผู้ประกอบการมีความสำคัญที่จะแยกแยะความแตกต่างจาก!(x==y) (!x)==y
jimmij

@jimmij คุณหมายความว่าเมื่อเปรียบเทียบสตริงนี้if [ ! "$string" = "one" ]แปลว่าหากไม่ได้ค่าเท่ากับ$string oneและนี่if [ "$string" != "one"]แปลว่าค่าของ$stringไม่เท่ากันoneหรือไม่?
Jimmy_A

5
@Jimmy_A ฉันหมายความว่าคุณต้องรู้ว่า "แปล" นี้เป็นอย่างไร การรวมตัวดำเนินการเข้าด้วยกัน ( !=ไวยากรณ์) นั้นชัดเจนยิ่งขึ้น
jimmij

เรียนผู้มีสิทธิเลือกตั้งอย่างใกล้ชิดคำตอบของStéphaneแสดงให้เห็นว่ามีพฤติกรรมที่แตกต่างกันอย่างสำคัญคำตอบที่ถูกต้องไม่ได้มีพื้นฐานมาจากความคิดเห็น แต่อย่างใด
Kevin

คำตอบ:


35

ข้างข้อโต้แย้งเครื่องสำอาง / การตั้งค่า, เหตุผลหนึ่งที่อาจเป็นไปได้ว่ามีการใช้งานมากขึ้นที่ล้มเหลวในกรณีมุมกว่าด้วย[ ! "$a" = "$b" ][ "$a" != "$b" ]

ทั้งสองกรณีควรมีความปลอดภัยหากการใช้งานเป็นไปตามอัลกอริทึม POSIXแต่ถึงแม้ในปัจจุบัน ตัวอย่างเช่นด้วยa='(' b=')':

$ (a='(' b=')'; busybox test "$a" != "$b"; echo "$?")
0
$ (a='(' b=')'; busybox test ! "$a" = "$b"; echo "$?")
1

สำหรับdashรุ่นก่อนหน้า 0.5.9 เช่น 0.5.8 ที่พบshใน Ubuntu 16.04 เช่น:

$ a='(' b=')' dash -c '[ "$a" != "$b" ]; echo "$?"'
0
$ a='(' b=')' dash -c '[ ! "$a" = "$b" ]; echo "$?"'
1

(แก้ไขใน 0.5.9 ดูhttps://www.mail-archive.com/dash@vger.kernel.org/msg00911.html )

การใช้งานเหล่านั้นถือว่า[ ! "(" = ")" ]เป็นเช่น [ ! "(" "text" ")" ]นั้น[ ! "text" ](ทดสอบว่า "text" เป็นสตริงว่าง) หรือไม่ในขณะที่ POSIX บังคับให้เป็น[ ! "x" = "y" ](ทดสอบ "x" และ "y" เพื่อความเท่าเทียมกัน) การใช้งานเหล่านั้นล้มเหลวเนื่องจากทำการทดสอบผิดในกรณีนั้น

โปรดทราบว่ายังมีรูปแบบอื่น:

! [ "$a" = "$b" ]

อันนั้นต้องใช้ POSIX เชลล์ (จะไม่ทำงานกับเชลล์เป้าหมายเดิม)

โปรดทราบว่าการใช้งานหลายอย่างมีปัญหากับ[ "$a" = "$b" ](และ[ "$a" != "$b" ]) เช่นกันและยังคงเหมือน[builtin ของ/bin/shบน Solaris 10 (Bourne shell, POSIX เชลล์ที่อยู่ใน/usr/xpg4/bin/sh) นั่นเป็นเหตุผลที่คุณเห็นสิ่งต่าง ๆ เช่น:

[ "x$a" != "x$b" ]

ในสคริปต์ที่พยายามพกพาไปยังระบบเก่า


ดังนั้นในคำอื่น ๆ ไวยากรณ์ทั้งสองทำเหมือนกันไม่มีความแตกต่างใด ๆ แต่ด้วย! "$a" = "b"คุณจะต้องระมัดระวังในการเขียนเพื่อระบุการเปรียบเทียบ จากตัวอย่างของคุณฉันเข้าใจว่าคำสั่งที่สองส่งคืนnot zeroซึ่งอาจเป็นประโยชน์หรือทำให้เกิดปัญหา มันอาจเป็นประโยชน์หากคุณต้องการออกหากพวกเขาไม่ตรงกันหรือหนักใจหากคุณต้องการดูว่าการเปรียบเทียบล้มเหลวหรือไม่
4159 Jimmy_A

2
@Jimmy_A ไม่มีในการใช้งานเหล่านั้น[ ! "$a" = "$b" ]เพียงแค่ล้มเหลวเมื่อ$aเป็น(และ$bเป็น)มันอ้างว่าพวกเขาเหมือนกันเมื่อพวกเขาไม่ได้, (ไม่ได้เป็นสายเดียวกันเป็น)แต่[การดำเนินการทดสอบที่ไม่ถูกต้องในกรณีที่
Stéphane Chazelas

อ่าฉันคิดว่าฉันเข้าใจแล้ว ที่หนึ่งและสามหมายถึงการตรวจสอบว่าเงื่อนไขเป็นจริงในขณะที่สองและสี่ถ้าเงื่อนไขเป็นเท็จ ดังนั้นรหัสสถานะการออกแตกต่างกัน โดยพื้นฐานแล้วมันบอกว่าตัวแปร 1 & 4 นั้นต่างกันและ 2 & 3 ไม่เท่ากัน
Jimmy_A

3
@Jimmy_A ไม่ คุณพลาดจุดไปแล้ว หากการใช้งานเหล่านี้เป็นไปตาม POSIX รหัสสถานะทั้งหมดจะเป็น 0
Wildcard

เพื่อให้แน่ใจว่าฉันเข้าใจสิ่งนี้ทำให้เดือดร้อนใจไปที่: [ ! "$a" = "$b" ]บางครั้งมีการจัดการอย่างไม่ถูกต้องในการใช้งานเชลล์ของ buggy (ซึ่งฉันคิดว่าการแก้ไขประโยคแรกของคำตอบมากขึ้นหรือน้อยลง)
Michael Burr

8

x != yไวยากรณ์จะดีกว่าเพราะ! x == yเป็นข้อผิดพลาดง่าย - ต้องมีความรู้ของผู้ประกอบการมีความสำคัญที่แตกต่างจากภาษาภาษา ไวยากรณ์! x == yอาจจะตีความว่าเป็น!(x == y)หรือ(!x) == yขึ้นอยู่กับลำดับความสำคัญของVS!=


ตัวอย่างเช่นในการc++ปฏิเสธ! มาก่อนการเปรียบเทียบ / ผู้ประกอบการสัมพันธ์ ==จึงรหัสต่อไปนี้:

#include<iostream>

using namespace std;

int main()
{
  int x=1, y=2;
  if(     x  != y   ) cout<<"true"<<endl; else cout<<"false"<<endl;
  if(  !  x  == y   ) cout<<"true"<<endl; else cout<<"false"<<endl;
  if(  !( x  == y ) ) cout<<"true"<<endl; else cout<<"false"<<endl;
  if(   (!x) == y   ) cout<<"true"<<endl; else cout<<"false"<<endl;
}

ผลตอบแทน

true
false
true
false

พฤติกรรมที่คล้ายกันสามารถสังเกตได้ในภาษาอื่น ๆ รวมถึงเช่นawk- เครื่องมือที่ใช้บ่อยในโลกยูนิกซ์


ในทางกลับกันการรวบรวมผู้ประกอบการด้วยกันผ่านทางx != yจะไม่นำไปสู่ความสับสนใด ๆ เป็นรูปแบบที่ดีขึ้น ยิ่งกว่านั้นการพูดทางเทคนิค !=มักไม่ใช่สอง แต่เป็นเพียงตัวดำเนินการหนึ่งดังนั้นควรประเมินผลได้เร็วกว่าการเปรียบเทียบแบบแยกกันแล้วจึงปฏิเสธ ดังนั้นแม้ว่าไวยากรณ์ทั้งสองจะทำงานใน bash ฉันขอแนะนำให้ทำตามx != yวิธีที่ง่ายต่อการอ่านและบำรุงรักษาโค้ดซึ่งเป็นไปตามตรรกะมาตรฐานบางอย่าง


4

การเรียงลำดับของสิ่งนี้เป็นไปตามความคิดเห็นอย่างมากเนื่องจากคำตอบนั้นขึ้นอยู่กับวิธีที่สมองของแต่ละบุคคลมีสาย ในขณะที่มันเป็นความจริงที่ความหมายNOT ( A == B )เหมือนกัน(A != B )หนึ่งอาจชัดเจนกับคนคนหนึ่งและอีกคนหนึ่ง นอกจากนี้ยังขึ้นอยู่กับบริบทด้วย ตัวอย่างเช่นถ้าฉันมีชุดธงความหมายอาจชัดเจนกว่าด้วยไวยากรณ์หนึ่งเหนืออีก:

if NOT ( fileHandleStatus == FS_OPEN )

ตรงข้ามกับ

if ( fileHandleStatus != FS_OPEN )

และแม้กระทั่งif ( FS_OPEN != fileHandleStatus )เป็นผลมาจากความสะดวกในการพิมพ์โดยไม่ตั้งใจ=แทนที่จะเป็น==ภาษาที่อดีตได้รับการมอบหมายและการทดสอบความเสมอภาคในภายหลัง (เช่น C) ...
Derobert
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.