คุณมีเคล็ดลับอะไรสำหรับการเล่นกอล์ฟใน Bash ฉันกำลังมองหาความคิดที่สามารถนำไปใช้กับปัญหารหัสกอล์ฟโดยทั่วไปซึ่งอย่างน้อยค่อนข้างเฉพาะกับ Bash (เช่น "ลบความคิดเห็น" ไม่ใช่คำตอบ) กรุณาโพสต์หนึ่งเคล็ดลับต่อคำตอบ
คุณมีเคล็ดลับอะไรสำหรับการเล่นกอล์ฟใน Bash ฉันกำลังมองหาความคิดที่สามารถนำไปใช้กับปัญหารหัสกอล์ฟโดยทั่วไปซึ่งอย่างน้อยค่อนข้างเฉพาะกับ Bash (เช่น "ลบความคิดเห็น" ไม่ใช่คำตอบ) กรุณาโพสต์หนึ่งเคล็ดลับต่อคำตอบ
คำตอบ:
ไม่มีเอกสารแต่ทำงานได้กับทุกเวอร์ชั่นที่ฉันใช้เพื่อsh
ความเข้ากันได้แบบเก่า:
for
ลูปช่วยให้คุณสามารถใช้แทน{
}
do
done
เช่นแทนที่:
for i in {1..10};do echo $i; done
ด้วย:
for i in {1..10};{ echo $i;}
sh
และ Bash ก็อนุญาตเพราะเหตุนี้ถึงแม้ว่าฉันจะเศร้าที่ไม่มีการอ้างอิง
csh
อาจเป็น - นั่นเป็นวิธีที่พวกเขาทำงานในเปลือกนั้น
ksh93
สิ่งข้างต้นอาจเป็น: ;{1..10}
และในbash
:printf %s\\n {1..10}
for((;i++<10)){ echo $i;}
สั้นกว่าfor i in {1..10};{ echo $i;}
สำหรับการขยายเลขคณิตให้ใช้$[…]
แทน$((…))
:
bash-4.1$ echo $((1+2*3))
7
bash-4.1$ echo $[1+2*3]
7
ในการขยายเลขคณิตไม่ใช้$
:
bash-4.1$ a=1 b=2 c=3
bash-4.1$ echo $[$a+$b*$c]
7
bash-4.1$ echo $[a+b*c]
7
การขยายเลขคณิตจะดำเนินการกับตัวห้อยอาร์เรย์ที่จัดทำดัชนีดังนั้นอย่าใช้$
ไม่ได้:
bash-4.1$ a=(1 2 3) b=2 c=3
bash-4.1$ echo ${a[$c-$b]}
2
bash-4.1$ echo ${a[c-b]}
2
ในการขยายเลขคณิตไม่ใช้${…}
:
bash-4.1$ a=(1 2 3)
bash-4.1$ echo $[${a[0]}+${a[1]}*${a[2]}]
7
bash-4.1$ echo $[a[0]+a[1]*a[2]]
7
while((i--))
ซึ่งใช้งานได้กับwhile[i--]
หรือใช้งานwhile $[i--]
ไม่ได้สำหรับฉัน GNU ทุบตีรุ่น 4.3.46 (1)
y=`bc<<<"($x*2.2)%10/1"`
... ตัวอย่างการใช้bc
สำหรับการคำนวณที่ไม่ใช่จำนวนเต็ม ... สังเกต/1
ที่ท้ายตัดทอนทศนิยมที่เกิดขึ้นให้เป็น int
s=$((i%2>0?s+x:s+y))
... ตัวอย่างการใช้โอเปอเรเตอร์ใน bash arithmetic มันสั้นกว่าif..then..else
หรือ[ ] && ||
GNU bash, version 5.0.2(1)-release (x86_64-apple-darwin16.7.0)
และมันไม่ได้อยู่ในเหมือง
วิธีปกติในการกำหนดความยาวและน่าเบื่อคือ
f(){ CODE;}
เมื่อชายคนนี้ค้นพบว่าคุณต้องการพื้นที่อย่างแน่นอนก่อนCODE
และอัฒภาคหลังจากนั้น
นี่เป็นเคล็ดลับเล็กน้อยที่ฉันได้เรียนรู้จาก@DigitalTrauma :
f()(CODE)
นั่นคืออักขระสองตัวที่สั้นกว่าและทำงานได้เช่นกันโดยที่คุณไม่จำเป็นต้องดำเนินการเปลี่ยนแปลงค่าของตัวแปรหลังจากฟังก์ชันส่งคืน ( วงเล็บจะเรียกใช้เนื้อความในเชลล์ย่อย )
ในฐานะที่เป็น@ jimmy23013ชี้ให้เห็นในความคิดเห็นที่แม้วงเล็บอาจจะไม่จำเป็น
คู่มือทุบตีอ้างอิงแสดงให้เห็นว่าฟังก์ชั่นสามารถกำหนดดังต่อไปนี้:
name () compound-command [ redirections ]
หรือ
function name [()] compound-command [ redirections ]
คำสั่งสารประกอบสามารถ:
until
, while
หรือfor
if
, case
, ((...))
หรือ[[...]]
(...)
หรือ{...}
นั่นหมายความว่าทั้งหมดต่อไปนี้ถูกต้อง:
$ f()if $1;then $2;fi
$ f()($1&&$2)
$ f()(($1)) # This one lets you assign integer values
และฉันใช้วงเล็บปีกกาเหมือนเครื่องดูด ...
f()while ...
f()if ...
และคำสั่งผสมอื่น ๆ
f()CODE
ถูกกฎหมาย ปรากฎว่าf()echo hi
ถูกกฎหมายใน pdksh และ zsh แต่ไม่ใช่ในทุบตี
for
เพราะมันเริ่มต้นที่ positionals: f()for x do : $x; done;set -x *;PS4=$* f "$@"
หรืออะไรบางอย่าง
เคล็ดลับเพิ่มเติม
ใช้โอเปอเรเตอร์ที่ไม่เหมาะสม((test)) && cmd1 || cmd2
หรือ[ test ] && cmd1 || cmd2
มากที่สุด
ตัวอย่าง (การนับความยาวจะไม่รวมบรรทัดบนสุดเสมอ):
t="$something"
if [ $t == "hi" ];then
cmd1
cmd2
elif [ $t == "bye" ];then
cmd3
cmd4
else
cmd5
if [ $t == "sup" ];then
cmd6
fi
fi
ด้วยการใช้ผู้ประกอบการที่สามเท่านั้นสิ่งนี้สามารถทำให้สั้นลงได้อย่างง่ายดาย:
t="$something"
[ $t == "hi" ]&&{
cmd1;cmd2
}||[ $t == "bye" ]&&{
cmd3;cmd4
}||{
cmd5
[ $t == "sup" ]&&cmd6
}
ตามที่ nyuszika7h ชี้ให้เห็นในความคิดเห็นตัวอย่างที่เฉพาะเจาะจงนี้อาจสั้นลงได้อีกโดยใช้case
:
t="$something"
case $t in "hi")cmd1;cmd2;;"bye")cmd3;cmd4;;*)cmd5;[ $t == "sup" ]&&cmd6;esac
นอกจากนี้ให้เลือกวงเล็บให้มากที่สุด เนื่องจากเครื่องหมายวงเล็บเป็นตัวอักษรและไม่ใช่คำจึงไม่จำเป็นต้องเว้นวรรคในบริบทใด ๆ นอกจากนี้ยังหมายถึงเรียกใช้คำสั่งจำนวนมากใน subshell ให้มากที่สุดเนื่องจากเครื่องหมายปีกกา (เช่น{
และ}
) เป็นคำสงวนไม่ใช่ตัวอักษรเมตาดังนั้นจึงต้องมีช่องว่างทั้งสองด้านในการแยกวิเคราะห์อย่างถูกต้อง แต่ meta-character ไม่ ฉันคิดว่าคุณรู้แล้วว่า subshells ไม่ส่งผลกระทบต่อสภาพแวดล้อมพาเรนต์ดังนั้นสมมติว่าคำสั่งตัวอย่างทั้งหมดสามารถรันได้อย่างปลอดภัยใน subshell (ซึ่งไม่ใช่เรื่องปกติในกรณีใด ๆ ) คุณสามารถย่อโค้ดข้างต้นนี้ :
t=$something
[ $t == "hi" ]&&(cmd1;cmd2)||[ $t == "bye" ]&&(cmd3;cmd4)||(cmd5;[ $t == "sup" ]&&cmd6)
นอกจากนี้หากคุณไม่สามารถทำได้การใช้วงเล็บยังสามารถย่อขนาดให้เล็กลงได้ สิ่งหนึ่งที่ต้องจำไว้ก็คือมันใช้งานได้เฉพาะสำหรับจำนวนเต็มซึ่งทำให้ไร้ประโยชน์สำหรับวัตถุประสงค์ของตัวอย่างนี้ (แต่มันดีกว่าการใช้-eq
สำหรับจำนวนเต็ม)
อีกสิ่งหนึ่งหลีกเลี่ยงคำพูดที่เป็นไปได้ เมื่อใช้คำแนะนำข้างต้นคุณสามารถย่อขนาดให้เล็กลงได้ ตัวอย่าง:
t=$something
[ $t == hi ]&&(cmd1;cmd2)||[ $t == bye ]&&(cmd3;cmd4)||(cmd5;[ $t == sup ]&&cmd6)
ในเงื่อนไขการทดสอบให้เลือกใช้วงเล็บเดี่ยวมากกว่าวงเล็บสองเท่าที่จะทำได้โดยมีข้อยกเว้นเล็กน้อย มันลดอักขระสองตัวฟรี แต่ในบางกรณีอาจไม่ทนทาน (เป็นส่วนขยายของ Bash - ดูตัวอย่างด้านล่าง) นอกจากนี้ใช้อาร์กิวเมนต์เท่ากับเดียวแทนที่จะเป็นสองเท่า มันเป็นตัวอักษรฟรีที่จะลดลง
[[ $f == b ]]&&: # ... <-- Bad
[ $f == b ]&&: # ... <-- Better
[ $f = b ]&&: # ... <-- Best. word splits and pathname-expands the contents of $f. Esp. bad if it starts with -
หมายเหตุข้อแม้นี้โดยเฉพาะอย่างยิ่งในการตรวจสอบเอาต์พุตว่างหรือตัวแปรที่ไม่ได้กำหนด:
[[ $f ]]&&: # double quotes aren't needed inside [[, which can save chars
[ "$f" = '' ]&&: <-- This is significantly longer
[ -n "$f" ]&&:
ในด้านเทคนิคทั้งหมดตัวอย่างเฉพาะนี้จะดีที่สุดกับcase
... in
:
t=$something
case $t in hi)cmd1;cmd2;;bye)cmd3;cmd4;;*)cmd5;[ $t == sup ]&&cmd6;esac
ดังนั้นคุณธรรมของการโพสต์นี้คือ:
if
/ if-else
/ ฯลฯ โครงสร้างcase
... in
เนื่องจากมันอาจบันทึกได้ไม่กี่ไบต์โดยเฉพาะในการจับคู่สตริงPS: นี่คือรายการของเมตาอักขระที่รู้จักใน Bash โดยไม่คำนึงถึงบริบท (และสามารถแยกคำ):
< > ( ) ; & | <space> <tab>
แก้ไข: ตามที่ manatwork ชี้ให้เห็นการทดสอบวงเล็บคู่นั้นใช้ได้กับจำนวนเต็มเท่านั้น นอกจากนี้ทางอ้อมฉันพบว่าคุณต้องมีช่องว่างรอบตัว==
ดำเนินการ แก้ไขโพสต์ของฉันด้านบน
ฉันยังขี้เกียจเกินไปที่จะคำนวณความยาวของแต่ละเซ็กเมนต์อีกครั้งดังนั้นฉันจึงลบมันออก มันควรจะง่ายพอที่จะหาเครื่องคิดเลขความยาวสตริงออนไลน์ได้หากจำเป็น
[ $t=="hi" ]
มักจะมีการประเมินถึง 0 [ -n "STRING" ]
ขณะที่มันถูกแยกวิเคราะห์เป็น (($t=="hi"))
จะประเมินเป็น 0 ตราบใดที่ $ t มีค่าที่ไม่ใช่ตัวเลขเนื่องจากสตริงจะถูกบังคับให้เป็นจำนวนเต็มในการประเมินทางคณิตศาสตร์ กรณีทดสอบบางอย่าง: pastebin.com/WefDzWbL
case
จะสั้นกว่าที่นี่ นอกจากนี้คุณไม่จำเป็นต้องมีช่องว่างมาก่อน}
แต่คุณต้องทำหลังจาก{
นั้น
=
มีประสิทธิภาพน้อยกว่า==
? =
ได้รับคำสั่งจาก POSIX ==
ไม่ใช่
แทนที่จะgrep -E
, grep -F
, grep -r
ใช้egrep
, fgrep
, rgrep
ประหยัดสองตัวอักษร อันที่สั้นกว่านั้นเลิกใช้แล้ว แต่ทำงานได้ดี
(คุณขอหนึ่งเคล็ดลับต่อคำตอบ!)
Pgrep
grep -P
แม้ว่าฉันจะเห็นว่ามันอาจจะสับสนได้ง่ายpgrep
ซึ่งใช้ในการค้นหากระบวนการ
องค์ประกอบ 0 ของอาเรย์สามารถเข้าถึงได้โดยใช้ชื่อตัวแปรเท่านั้นการบันทึกห้าไบต์ผ่านการระบุดัชนี 0 อย่างชัดเจน:
$ a=(code golf)
$ echo ${a[0]}
code
$ echo $a
code
$
หากคุณต้องการส่งเนื้อหาของตัวแปรไปยัง STDIN ของกระบวนการถัดไปในไปป์ไลน์มันเป็นเรื่องปกติที่จะสะท้อนตัวแปรลงในไพพ์ไลน์ แต่คุณสามารถบรรลุสิ่งเดียวกันด้วยการ<<<
ทุบตีที่นี่สตริง :
$ s="code golf"
$ echo "$s"|cut -b4-6
e g
$ cut -b4-6<<<"$s"
e g
$
s=code\ golf
, echo $s|
และ<<<$s
(ทำให้ทราบว่าทั้งสองฝ่ายทำงานเพียงเพราะไม่มีช่องว่างซ้ำ ฯลฯ )
หลีกเลี่ยง$( ...command... )
มีทางเลือกอื่นที่ช่วยประหยัดถ่านหนึ่งตัวและทำสิ่งเดียวกัน
` ...command... `
$( )
จำเป็นถ้าคุณมีการทดแทนคำสั่งซ้อนกัน; ไม่งั้นคุณจะต้องหลบหนีจากด้านใน``
$()
เมื่อฉันต้องการเรียกใช้การทดแทนบนเครื่องของฉันแทนที่จะเป็นscp
เครื่องเป้าหมาย ในกรณีส่วนใหญ่พวกเขาเหมือนกัน
$()
สามารถทำได้ถ้าคุณพูดอย่างถูกต้อง (ยกเว้นว่าคุณต้องการคำสั่งของคุณเพื่อเอาตัวรอดจากบางสิ่งที่ munges $
แต่ไม่ใช่ backticks) มีความแตกต่างเล็กน้อยในการอ้างอิงสิ่งที่อยู่ภายใน mywiki.wooledge.org/BashFAQ/082อธิบายถึงความแตกต่าง ถ้าคุณไม่เล่นกอล์ฟห้ามใช้ backticks
echo `bc <<<"\`date +%s\`-12"`
... (มันยากที่จะโพสต์ตัวอย่างที่มี backtick ในความคิดเห็นมี!;)
if
เพื่อจัดกลุ่มคำสั่งเมื่อเทียบกับเคล็ดลับนี้ซึ่งเอาที่ทั้งหมดนี้ควรจะทำงานได้ดีขึ้นในกรณีที่หายากมากบางอย่างเช่นเมื่อคุณต้องการค่าผลตอบแทนจากif
if
หากคุณมีกลุ่มคำสั่งซึ่งลงท้ายด้วย a if
เช่นนี้:
a&&{ b;if c;then d;else e;fi;}
a&&(b;if c;then d;else e;fi)
คุณสามารถตัดคำสั่งก่อนหน้าif
ในเงื่อนไขแทน:
a&&if b;c;then d;else e;fi
หรือถ้าฟังก์ชันของคุณลงท้ายด้วยif
:
f(){ a;if b;then c;else d;fi;}
คุณสามารถลบเครื่องมือจัดฟัน:
f()if a;b;then c;else d;fi
[test] && $if_true || $else
ในฟังก์ชั่นเหล่านี้และบันทึกบางไบต์
&&
และ||
(( ... ))
สำหรับเงื่อนไขคุณสามารถแทนที่:
if [ $i -gt 5 ] ; then
echo Do something with i greater than 5
fi
โดย
if((i>5));then
echo Do something with i greater than 5
fi
(หมายเหตุ: ไม่มีที่ว่างหลังจากนั้นif
)
หรือแม้กระทั่ง
((i>5))&&{
echo Do something with i greater than 5
}
... หรือถ้ามีเพียงคำสั่งเดียว
((i>5))&&echo Echo or do something with i greater than 5
((i>5?c=1:0))&&echo Nothing relevant there...
# ...
((c))&&echo Doing something else if i was greater than 5
หรือเหมือนกัน
((c=i>5?c=0,1:0))&&echo Nothing relevant there...
# ...
((c))&&echo Doing something else if i was greater than 5
... ที่ไหนถ้า i> 5 ดังนั้น c = 1 (ไม่ใช่ 0;)
[ ]
(())
[ ]
คุณต้องการเครื่องหมายดอลลาร์สำหรับตัวแปร [ ]
ฉันไม่เห็นว่าคุณสามารถทำเช่นเดียวกันที่มีความยาวเดียวกันหรือขนาดเล็กโดยใช้
((...))
ไม่จำเป็นต้องขึ้นบรรทัดใหม่หรือเว้นวรรค เช่นfor((;10>n++;)){((n%3))&&echo $n;}
ลองออนไลน์!
ไวยากรณ์ที่สั้นกว่าสำหรับลูปไม่ จำกัด (ซึ่งสามารถหลบหนีด้วยbreak
หรือexit
คำสั่ง) คือ
for((;;)){ code;}
นี้จะสั้นกว่าและwhile true;
while :;
หากคุณไม่ต้องการbreak
(ด้วยexit
วิธีเดียวที่จะหลบหนี) คุณสามารถใช้ฟังก์ชันเรียกซ้ำได้
f(){ code;f;};f
หากคุณต้องการหยุดพัก แต่คุณไม่ต้องการออกและคุณไม่จำเป็นต้องดำเนินการแก้ไขตัวแปรใด ๆ นอกลูปคุณสามารถใช้ฟังก์ชันเรียกซ้ำพร้อมวงเล็บรอบ ๆ ร่างกายซึ่งเรียกใช้ฟังก์ชันของฟังก์ชั่นใน subshell
f()(code;f);f
for
ลูปหนึ่งบรรทัดนิพจน์ทางคณิตศาสตร์ที่ต่อกับส่วนขยายช่วงจะถูกประเมินสำหรับแต่ละรายการในช่วง ตัวอย่างเช่นต่อไปนี้:
: $[expression]{0..9}
จะประเมินexpression
10 ครั้ง
มักจะสั้นกว่าfor
ลูปที่เทียบเท่า:
for((;10>n++;expression with n)){ :;}
: $[expression with ++n]{0..9}
หากคุณไม่สนใจคำสั่งที่ไม่พบข้อผิดพลาดคุณสามารถลบ inital :
ได้ สำหรับการวนซ้ำที่มากกว่า 10 คุณยังสามารถใช้ช่วงอักขระได้เช่น{A..z}
จะวนซ้ำ 58 ครั้ง
เป็นตัวอย่างที่ใช้งานได้จริงดังต่อไปนี้สร้างหมายเลขสามเหลี่ยม 50 หมายเลขแรกซึ่งแต่ละรายการอยู่ในสายของตนเอง:
for((;50>d++;)){ echo $[n+=d];} # 31 bytes
printf %d\\n $[n+=++d]{A..r} # 28 bytes
for((;0<i--;)){ f;}
ตามที่ระบุไว้ในทุบตี“สำหรับ” วงโดยไม่ต้องมีส่วนร่วม“ในแถบ foo ...”ที่in "$@;"
ในfor x in "$@;"
ซ้ำซ้อน
จากhelp for
:
for: for NAME [in WORDS ... ] ; do COMMANDS; done
Execute commands for each member in a list.
The `for' loop executes a sequence of commands for each member in a
list of items. If `in WORDS ...;' is not present, then `in "$@"' is
assumed. For each element in WORDS, NAME is set to that element, and
the COMMANDS are executed.
Exit Status:
Returns the status of the last command executed.
ตัวอย่างเช่นถ้าเราต้องการที่จะยกกำลังสองจำนวนตัวเลขทั้งหมดที่ได้รับข้อโต้แย้งตำแหน่งเพื่อ Bash script หรือฟังก์ชั่นเราสามารถทำเช่นนี้
for n;{ echo $[n*n];}
สมมติว่าคุณกำลังพยายามอ่านไฟล์และใช้งานในสิ่งอื่น สิ่งที่คุณอาจทำคือ:
echo foo `cat bar`
หากเนื้อหาของbar
เป็นนี้จะพิมพ์foobar
foo foobar
อย่างไรก็ตามมีทางเลือกอื่นหากคุณใช้วิธีนี้ซึ่งจะช่วยประหยัด 3 ไบต์:
echo foo `<bar`
<bar
ด้วยตัวเองไม่ทำงาน แต่วางไว้ใน backticks ไม่?
<
ทำให้ไฟล์ที่จะสั่ง แต่ในกรณีนี้มันทำให้มันเป็นมาตรฐานการส่งออกเนื่องจากมุมแหลม Backticks ประเมินสิ่งนี้ด้วยกัน
`cat`
?
[
แทน[[
และtest
เมื่อเป็นไปได้ตัวอย่าง:
[ -n $x ]
=
แทน==
การเปรียบเทียบตัวอย่าง:
[ $x = y ]
โปรดทราบว่าคุณต้องมีช่องว่างรอบเครื่องหมายเท่ากับมิฉะนั้นจะใช้งานไม่ได้ เช่นเดียวกับ==
การทดสอบของฉัน
[
... ]
== /bin/test
แต่[[
... ]]
! = /bin/test
และหนึ่งไม่ควรชอบ[
... ]
มากกว่า[[
... ]]
นอก codegolf
tr -cd
สั้นกว่า grep -o
ตัวอย่างเช่นหากคุณต้องการนับช่องว่างgrep -o <char>
(พิมพ์เฉพาะส่วนที่ตรงกัน) ให้ 10 ไบต์ในขณะที่tr -cd <char>
(ลบส่วนเติมเต็ม<char>
) ให้ 9
# 16 bytes
grep -o \ |wc -l
# 15 bytes
tr -cd \ |wc -c
(ที่มา )
โปรดทราบว่าพวกเขาทั้งสองให้ผลลัพธ์ที่แตกต่างกันเล็กน้อย grep -o
ส่งคืนผลลัพธ์ที่คั่นด้วยบรรทัดขณะที่tr -cd
ให้ทั้งหมดในบรรทัดเดียวกันดังนั้นtr
อาจไม่เป็นผลดีเสมอไป
ในความท้าทายเมื่อเร็ว ๆ นี้ฉันพยายามอ่านไฟล์/sys/class/power_supply/BAT1/capacity
อย่างไรก็ตามสิ่งนี้สามารถย่อให้เล็กลงได้/*/*/*/*/capac*y
เนื่องจากไม่มีไฟล์อื่นอยู่ในรูปแบบนั้น
ตัวอย่างเช่นถ้าคุณมีไดเรกทอรีfoo/
ที่มีไฟล์foo, bar, foobar, barfoo
และคุณต้องการที่จะอ้างอิงไฟล์foo/barfoo
คุณสามารถใช้foo/barf*
เพื่อบันทึกไบต์
*
"หมายถึงอะไร" และเทียบเท่ากับ .*
regex
ใช้ท่อไปยังคำสั่งแทน:
ในตัวจะกินการป้อนข้อมูลทั้งหมด/dev/null
:
echo a|tee /dev/stderr|:
จะไม่พิมพ์อะไรเลย
echo a|tee /dev/stderr|:
พิมพ์บนคอมพิวเตอร์ของฉัน แต่ที่อื่น SIGPIPE อาจฆ่าทีก่อน tee
มันอาจจะขึ้นอยู่กับรุ่นของ
tee >(:) < <(seq 1 10)
งานได้ แต่tee /dev/stderr | :
จะไม่ใช้ แม้a() { :;};tee /dev/stderr < <(seq 1 10)| a
จะไม่พิมพ์อะไรเลย
:
แท้จริงไม่ได้กินเลย ... หากคุณใส่อินพุตไปยังลำไส้ใหญ่คุณอาจทำให้ท่อไหลผิดพลาด ... แต่คุณสามารถลอยการเปลี่ยนเส้นทาง โดยโคลอนหรือวางกระบวนการด้วย ... :| while i>&$(($??!$?:${#?})) command shit; do [ -s testitsoutput ]; done
หรืออย่างไรก็ตามข้อเสนอแนะหลอกใช้ ... เช่นกันคุณรู้หรือไม่ว่าผีฉันเกือบจะเป็นฉันเหรอ? ... หลีกเลี่ยงค่าใช้จ่ายทั้งหมด< <(psycho shit i can alias to crazy math eat your world; okay? anyway, ksh93 has a separate but equal composite char placement)
split
มีอีก (เลิกใช้ แต่ไม่มีใครใส่ใจ) ไวยากรณ์สำหรับการป้อนข้อมูลแยกเป็นส่วนของN
เส้นแต่ละแทนsplit -lN
คุณสามารถใช้เช่นsplit -N
split -9
โดยพื้นฐานแล้วเชลล์เป็นภาษาแมโครชนิดหนึ่งหรืออย่างน้อยไฮบริดหรือบางชนิด บรรทัดคำสั่งทุกบรรทัดสามารถแบ่งออกเป็นสองส่วนโดยทั่วไป: ส่วนการแยกวิเคราะห์ / อินพุตและส่วนขยาย / เอาท์พุท
ส่วนแรกคือสิ่งที่คนส่วนใหญ่มุ่งเน้นเพราะมันง่ายที่สุด: คุณเห็นสิ่งที่คุณได้รับ ส่วนที่สองคือสิ่งที่หลายคนหลีกเลี่ยงไม่ได้แม้กระทั่งพยายามที่จะเข้าใจดีมากและเป็นเหตุผลว่าทำไมผู้คนพูดถึงสิ่งต่าง ๆ เช่นeval
ความชั่วร้ายและอ้างถึงการขยายของคุณ - ผู้คนต้องการผลลัพธ์ของส่วนแรกให้เท่ากันก่อน ไม่เป็นไร - แต่มันนำไปสู่การขยายสาขารหัสที่ไม่จำเป็นโดยไม่จำเป็นและการทดสอบที่ไม่เกี่ยวข้องมากมาย
ขยายมีการทดสอบตัวเอง ${param[[:]#%+-=?]word}
รูปแบบที่มีมากเกินพอที่จะตรวจสอบเนื้อหาของพารามิเตอร์ที่มี Nestable และทุกคนตามรอบการประเมินสำหรับNUL - ซึ่งเป็นสิ่งที่คนส่วนใหญ่คาดหวังของการทดสอบอยู่แล้ว +
มีประโยชน์เป็นพิเศษในลูป:
r()while IFS= read -r r&&"${r:+set}" -- "$@" "${r:=$*}";do :;done 2>&-
IFS=x
printf %s\\n some lines\ of input here '' some more|{ r;echo "$r"; }
somexlines ofxinputxhere
... ในขณะที่read
ดึงในบรรทัดว่างไม่"${r:+set}"
ขยาย"set"
และตำแหน่งได้รับการ$r
ต่อท้าย แต่เมื่อบรรทัดว่างเป็นread
, $r
เป็นที่ว่างเปล่าและ"${r:+set}"
ขยายไป""
- ซึ่งเป็นที่ไม่ถูกต้องคำสั่ง แต่เนื่องจากบรรทัดคำสั่งถูกขยายก่อนที่""
คำสั่ง null จะถูกค้นหาจึง"${r:=$*}"
ใช้ค่าของ positionals ทั้งหมดที่ต่อกันบนไบต์แรก$IFS
ด้วย r()
อาจถูกเรียกอีกครั้งใน|{
คำสั่งผสม;}
ด้วยค่าที่แตกต่างกันสำหรับ$IFS
การรับย่อหน้าอินพุตถัดไปเช่นกันเนื่องจากเป็นสิ่งผิดกฎหมายสำหรับเชลล์ที่read
จะบัฟเฟอร์เกิน\n
ewline ถัดไปในอินพุต
ใช้การเรียกซ้ำหางเพื่อทำให้ลูปสั้นลง:
สิ่งเหล่านี้เทียบเท่ากับพฤติกรรม (แม้ว่าอาจไม่ได้อยู่ในการใช้งานหน่วยความจำ / PID):
while :;do body; done
f()(body;f);f
body;exec $0
body;$0
และสิ่งเหล่านี้เทียบเท่ากันโดยประมาณ:
while condition; do body; done
f()(body;condition&&f);f
body;condition&&exec $0
body;condition&&$0
(ในทางเทคนิคทั้งสามครั้งล่าสุดจะดำเนินการร่างกายอย่างน้อยหนึ่งครั้ง)
การใช้$0
ต้องให้สคริปต์ของคุณอยู่ในไฟล์ไม่ใช่วางลงในพรอมต์ bash
ในที่สุดสแต็กของคุณอาจล้น แต่คุณบันทึกบางไบต์
บางครั้งก็จะสั้นกว่าที่จะใช้ในตัวสำหรับการแสดงผลของการแสดงออกทางคณิตศาสตร์ที่เรียบง่ายแทนปกติexpr
echo $[ ]
ตัวอย่างเช่น:
expr $1 % 2
หนึ่งไบต์สั้นกว่า:
echo $[$1%2]
pwd
แทนecho
การสร้างบรรทัดเอาต์พุตต้องการวางบรรทัดบน stdout แต่ไม่สนใจเนื้อหาและต้องการ จำกัด คำตอบของคุณสำหรับ shell builtins? เป็นไบต์สั้นกว่าpwd
echo
สามารถละเว้นเครื่องหมายคำพูดได้เมื่อพิมพ์สตริง
echo "example"
echo example
เอาต์พุตใน SM-T335 LTE, Android 5.1.1:
u0_a177@milletlte:/ $ echo "example"
example
u0_a177@milletlte:/ $ echo example
example
เมื่อกำหนดไอเท็มอาเรย์ที่ไม่ต่อเนื่องคุณยังสามารถข้ามดัชนีต่อเนื่องของกลุ่มต่อเนื่อง:
bash-4.4$ a=([1]=1 [2]=2 [3]=3 [21]=1 [22]=2 [23]=3 [31]=1)
bash-4.4$ b=([1]=1 2 3 [21]=1 2 3 [31]=1)
ผลลัพธ์เหมือนกัน:
bash-4.4$ declare -p a b
declare -a a=([1]="1" [2]="2" [3]="3" [21]="1" [22]="2" [23]="3" [31]="1")
declare -a b=([1]="1" [2]="2" [3]="3" [21]="1" [22]="2" [23]="3" [31]="1")
ตามman bash
:
อาร์เรย์ได้รับมอบหมายให้ใช้การกำหนดสารประกอบของแบบฟอร์มชื่อ = (มูลค่า1 ... ค่าn ) ซึ่งแต่ละค่าจะอยู่ในรูป [ ห้อย ] = สตริง ที่ได้รับมอบหมายอาร์เรย์จัดทำดัชนีไม่จำเป็นต้องมีอะไร แต่ สตริง เมื่อกำหนดให้กับอาร์เรย์ที่มีการทำดัชนีหากมีการใส่วงเล็บและตัวห้อยที่เป็นตัวเลือกดัชนีนั้นจะถูกกำหนดให้; มิฉะนั้นดัชนีขององค์ประกอบที่กำหนดเป็นดัชนีสุดท้ายที่กำหนดโดยคำสั่งบวกหนึ่ง
หากสตริงอยู่ในตัวแปรa
และไม่มีตัวอักษรยกเว้นและรูปแบบ ( \
และ%
) ให้ใช้สิ่งนี้:
printf $a
แต่มันจะยาวกว่ารหัสต่อไปนี้หากต้องการบันทึกผลลัพธ์ลงในตัวแปรแทนที่จะพิมพ์:
x=($a)
$x
for
คำสั่ง:for ((l=i=0;l<=99;i=i>98?l++,0:++i)) ;do
printf "I: %2d, L: %2d\n" $i $l
done |
tee >(wc) | (head -n4;echo ...;tail -n 5)
I: 0, L: 0
I: 1, L: 0
I: 2, L: 0
I: 3, L: 0
...
I: 96, L: 99
I: 97, L: 99
I: 98, L: 99
I: 99, L: 99
10000 40000 130000
หากคุณต้องการกำหนดสตริงที่ยกมาให้กับตัวแปรแล้วพิมพ์ค่าของตัวแปรนั้นดังนั้นวิธีปกติในการทำเช่นนั้นคือ:
a="Programming Puzzles & Code Golf";echo $a
หากa
ก่อนหน้านี้ไม่มีการตั้งค่าสิ่งนี้อาจสั้นลงไปที่:
echo ${a=Programming Puzzles & Code Golf}
หากa
ตั้งค่าไว้ก่อนหน้านี้ควรใช้สิ่งนี้แทน:
echo ${a+Programming Puzzles & Code Golf}
หมายเหตุสิ่งนี้มีประโยชน์ก็ต่อเมื่อสตริงต้องมีเครื่องหมายอัญประกาศ ไม่มีคำพูดa=123;echo $a
สั้น ๆ
${a+foo}
a
ไม่ได้ตั้งค่า
sh
อะไรและเชลล์อนุญาตให้for
ไวยากรณ์นี้คืออะไรzsh
จะได้รับอนุญาตอย่างชัดแจ้งใน