ด้วยพื้นเปลือกใด ๆ :
printf '{ PS4=\${$(($#-$x))}; } 2>&3; 2>&1\n%.0s' |
x=LINENO+1 sh -sx "$@" 3>/dev/null
และคุณไม่จำเป็นต้องใช้ subshells ตัวอย่างเช่น:
set -x a b c
{ last= PS4=\${last:=\${$#}}; set +x; } 2>/dev/null
echo "$last"
... พิมพ์ ...
c
และนี่คือฟังก์ชั่นเชลล์ที่สามารถตั้งค่าเชลล์aliasสำหรับคุณที่จะพิมพ์อาร์กิวเมนต์ทั้งไปข้างหน้าหรือข้างหลัง:
tofro() case $1 in (*[!0-9]*|'') ! :;;(*) set "$1"
        until   [ "$1" -eq "$(($#-1))" ]    &&
                shift && alias args=":; printf \
            \"%.\$((\$??\${#*}:0))s%.\$((!\$??\${#*}:0))s\n\" $* "
        do      [ "$#" -gt 1 ] &&
                set "$@ \"\${$#}\" " '"${'"$((1+$1-$#))"'}"' ||
                set "$1" '"$1" "${'"$1"'}"'
        done;   esac
มันไม่ได้พยายามที่จะเก็บค่าที่แท้จริงสำหรับการขัดแย้งใด ๆ แต่มันจะทำให้สตริงเช่นนี้ในargs alias:
:;printf    "%.$(($??${#*}:0))s%.$((!$??${#*}:0))s\n" \
            "$1" "${3}" "${2}"  "${2}" "${3}"  "${1}"
... และเก็บเฉพาะการอ้างอิงพารามิเตอร์ย้อนหลังและไปข้างหน้า มันจะเก็บได้ถึงจำนวนที่ได้รับมันเป็นข้อโต้แย้ง และดังนั้นสิ่งที่aliasถูกสร้างขึ้นเช่น:
tofro 3
printfพฤติกรรมของได้รับผลกระทบโดยขึ้นอยู่กับค่าส่งคืนของคำสั่งก่อนหน้าซึ่งมักจะ:เป็นคำสั่ง null และมักจะเป็นจริง printfจะข้ามข้อโต้แย้งไปครึ่งหนึ่งในแต่ละครั้งที่พิมพ์ซึ่งตามค่าเริ่มต้นจะรับอาร์กิวเมนต์ที่พิมพ์จากหมายเลขที่เล็กที่สุดไปหามากที่สุด อย่างไรก็ตามถ้าคุณทำ:
! args
... มันพิมพ์กลับด้าน
เนื่องจากนามแฝงไม่ได้เก็บค่าตามตัวอักษรใด ๆ ค่าของมันจะยังคงอยู่ในขณะที่ args ที่แท้จริงอาจมีการเปลี่ยนแปลง แต่มันจะยังคงอ้างอิงมากที่สุดเท่าที่จะทำได้ ตัวอย่างเช่น:
set one two three
tofro 3
args; ! args
shift; args; ! args
... ที่พิมพ์ ...
one
two
three
three
two
one
two
three
three
two
แต่การรีเซ็ตนามแฝงสามารถทำได้เช่น:
tofro 2
args; ! args
... และมันจะพิมพ์ ...
two
three
three
two
               
              
argเนื่องจากมีการสั่งซื้ออย่างถูกต้องและไม่ย้อนกลับ เพื่อการใช้งานของexprฉันถูก จำกัด ให้ใช้มาตรฐานเท่านั้น