Với cơ bản bất kỳ vỏ:
printf '{ PS4=\${$(($#-$x))}; } 2>&3; 2>&1\n%.0s' |
x=LINENO+1 sh -sx "$@" 3>/dev/null
Và bạn không cần phải sử dụng subshells. Ví dụ:
set -x a b c
{ last= PS4=\${last:=\${$#}}; set +x; } 2>/dev/null
echo "$last"
... bản in ...
c
Và đây là một hàm shell có thể đặt shell alias
cho bạn, nó sẽ in các đối số tiến hoặc lùi:
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
Nó không cố lưu trữ các giá trị theo nghĩa đen cho bất kỳ đối số nào, mà thay vào đó, nó đặt một chuỗi như thế này trong args
alias
:
:;printf "%.$(($??${#*}:0))s%.$((!$??${#*}:0))s\n" \
"$1" "${3}" "${2}" "${2}" "${3}" "${1}"
... và do đó, các cửa hàng chỉ tham chiếu đến các tham số ngược và xuôi. Nó sẽ lưu trữ đến một số lượng như được đưa ra như là một đối số. Và do đó, những điều trên alias
đã được tạo ra như sau:
tofro 3
printf
Hành vi của bị ảnh hưởng dựa trên giá trị trả về của lệnh trước - luôn luôn :
là lệnh null và thường là đúng. printf
sẽ bỏ qua một nửa số đối số của nó mỗi lần nó in - theo mặc định, sẽ lấy các đối số được in ra từ số nhỏ nhất đến lớn nhất. Tuy nhiên, nếu bạn chỉ làm:
! args
... Nó in chúng ngược lại.
Bởi vì bí danh không lưu trữ bất kỳ giá trị bằng chữ nào, giá trị của nó vẫn ở trạng thái tĩnh trong khi các đối số thực tế có thể thay đổi, nhưng nó vẫn sẽ tham chiếu nhiều nhất có thể. Ví dụ:
set one two three
tofro 3
args; ! args
shift; args; ! args
... mà in ...
one
two
three
three
two
one
two
three
three
two
Nhưng đặt lại bí danh có thể được thực hiện như sau:
tofro 2
args; ! args
... và vì vậy nó in ...
two
three
three
two
arg
vì chúng được sắp xếp chính xác và không ngược lại. Đối với việc sử dụngexpr
, tôi chỉ giới hạn sử dụng tiêu chuẩn.