Câu trả lời:
Tôi đã trả lời câu hỏi như đã viết và mã này đảo ngược mảng. (In các phần tử theo thứ tự ngược mà không đảo ngược mảng chỉ là một for
vòng lặp đếm ngược từ phần tử cuối cùng về không.) Đây là thuật toán "trao đổi trước và cuối" tiêu chuẩn.
array=(1 2 3 4 5 6 7)
min=0
max=$(( ${#array[@]} -1 ))
while [[ min -lt max ]]
do
# Swap current first and last elements
x="${array[$min]}"
array[$min]="${array[$max]}"
array[$max]="$x"
# Move closer
(( min++, max-- ))
done
echo "${array[@]}"
Nó hoạt động cho các mảng có chiều dài lẻ và chẵn.
Một cách tiếp cận khác thường:
#!/bin/bash
array=(1 2 3 4 5 6 7)
f() { array=("${BASH_ARGV[@]}"); }
shopt -s extdebug
f "${array[@]}"
shopt -u extdebug
echo "${array[@]}"
Đầu ra:
7 6 5 4 3 2 1
Nếu extdebug
được bật, mảng BASH_ARGV
chứa trong một hàm tất cả các tham số vị trí theo thứ tự ngược lại.
Cách tiếp cận độc đáo (tất cả không thuần túy bash
):
nếu tất cả các phần tử trong một mảng chỉ là một ký tự (như trong câu hỏi), bạn có thể sử dụng rev
:
echo "${array[@]}" | rev
nếu không thì:
printf '%s\n' "${array[@]}" | tac | tr '\n' ' '; echo
và nếu bạn có thể sử dụng zsh
:
echo ${(Oa)array}
tac
, như đối diện của cat
khá tốt để nhớ, CẢM ƠN!
rev
, tôi cần phải đề cập rằng nó rev
sẽ không hoạt động chính xác cho các số có hai chữ số. Ví dụ, một phần tử mảng 12
sử dụng rev sẽ được in dưới dạng 21
. Hãy dùng thử ;-)
Nếu bạn thực sự muốn đảo ngược trong một mảng khác:
reverse() {
# first argument is the array to reverse
# second is the output array
declare -n arr="$1" rev="$2"
for i in "${arr[@]}"
do
rev=("$i" "${rev[@]}")
done
}
Sau đó:
array=(1 2 3 4)
reverse array foo
echo "${foo[@]}"
Cung cấp:
4 3 2 1
Điều này sẽ xử lý chính xác các trường hợp thiếu chỉ mục mảng, giả sử bạn đã có array=([1]=1 [2]=2 [4]=4)
, trong trường hợp đó, việc lặp từ 0 đến chỉ mục cao nhất có thể thêm các phần tử bổ sung, trống ,.
shellcheck
in hai cảnh báo: array=(1 2 3 4)
<-- SC2034: array appears unused. Verify it or export it.
và:echo "${foo[@]}"
<-- SC2154: foo is referenced but not assigned.
declare
dòng dành cho.
declare -n
dường như không hoạt động trong các phiên bản bash trước 4.3.
Để hoán đổi vị trí mảng tại chỗ (ngay cả với mảng thưa thớt) (kể từ bash 3.0):
#!/bin/bash
# Declare an sparse array to test:
array=([5]=101 [6]=202 [10]=303 [11]=404 [20]=505 [21]=606 [40]=707)
echo "Initial array values"
declare -p array
swaparray(){ local temp; temp="${array[$1]}"
array[$1]="${array[$2]}"
array[$2]="$temp"
}
ind=("${!array[@]}") # non-sparse array of indexes.
min=-1; max="${#ind[@]}" # limits to one before real limits.
while [[ min++ -lt max-- ]] # move closer on each loop.
do
swaparray "${ind[min]}" "${ind[max]}" # Exchange first and last
done
echo "Final Array swapped in place"
declare -p array
echo "Final Array values"
echo "${array[@]}"
Thực hiện:
./script
Initial array values
declare -a array=([5]="101" [6]="202" [10]="303" [11]="404" [20]="505" [21]="606" [40]="707")
Final Array swapped in place
declare -a array=([5]="707" [6]="606" [10]="505" [11]="404" [20]="303" [21]="202" [40]="101")
Final Array values
707 606 505 404 303 202 101
Đối với bash cũ hơn, bạn cần sử dụng một vòng lặp (trong bash (kể từ 2.04)) và sử dụng $a
để tránh không gian dấu:
#!/bin/bash
array=(101 202 303 404 505 606 707)
last=${#array[@]}
a=""
for (( i=last-1 ; i>=0 ; i-- ));do
printf '%s%s' "$a" "${array[i]}"
a=" "
done
echo
Đối với bash kể từ 2.03:
#!/bin/bash
array=(101 202 303 404 505 606 707)
last=${#array[@]}
a="";i=0
while [[ last -ge $((i+=1)) ]]; do
printf '%s%s' "$a" "${array[ last-i ]}"
a=" "
done
echo
Ngoài ra (sử dụng toán tử phủ định bitwise) (kể từ bash 4.2+):
#!/bin/bash
array=(101 202 303 404 505 606 707)
last=${#array[@]}
a=""
for (( i=0 ; i<last ; i++ )); do
printf '%s%s' "$a" "${array[~i]}"
a=" "
done
echo
Xấu xí, không thể nhầm lẫn, nhưng một lót:
eval eval echo "'\"\${array['{$((${#array[@]}-1))..0}']}\"'"
eval eval echo "'\"\${array[-'{1..${#array[@]}}']}\"'"
.
ind=("${!array[@]}");eval eval echo "'\"\${array[ind[-'{1..${#array[@]}}']]}\"'"
Mặc dù tôi sẽ không nói điều gì mới và tôi cũng sẽ sử dụng tac
để đảo ngược mảng, nhưng mặc dù điều đó sẽ đáng để đề cập đến giải pháp dòng đơn dưới đây bằng bash phiên bản 4.4:
$ read -d'\n' -a array < <(printf '%s\n' "${array[@]}" |tac)
Kiểm tra:
$ array=(1 2 3 4 5 6 10 11 12)
$ echo "${array[@]}"
1 2 3 4 5 6 10 11 12
$ read -d'\n' -a array < <(printf '%s\n' "${array[@]}"|tac)
$ echo "${array[@]}"
12 11 10 6 5 4 3 2 1
Lưu ý rằng tên var bên trong read là tên như mảng ban đầu, vì vậy không có mảng trợ giúp nào được yêu cầu để lưu trữ tạm thời.
Thực hiện thay thế bằng cách điều chỉnh IFS:
$ IFS=$'\n' read -d '' -a array < <(printf '%s\n' "${array[@]}"|tac);declare -p array
declare -a array=([0]="12" [1]="11" [2]="10" [3]="6" [4]="5" [5]="4" [6]="3" [7]="2" [8]="1")
PS: Tôi nghĩ các giải pháp trên sẽ không hoạt động trong bash
phiên bản dưới đây4.4
do read
triển khai chức năng dựng sẵn bash khác nhau .
IFS
phiên bản hoạt động nhưng nó cũng được in: declare -a array=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="10" [7]="11" [8]="12")
. Sử dụng bash 4.4-5
. Bạn có để loại bỏ ;declare -p array
vào cuối dòng đầu tiên, sau đó nó hoạt động ...
declare -p
chỉ là một cách nhanh chóng để làm cho bash in mảng thực (chỉ mục và nội dung). Bạn không cần declare -p
lệnh này trong kịch bản thực sự của bạn. Nếu có lỗi xảy ra trong các bài tập mảng của bạn, bạn có thể kết thúc trong trường hợp ${array[0]}="1 2 3 4 5 6 10 11 12"
= tất cả các giá trị được lưu trong cùng một chỉ mục - sử dụng echo bạn sẽ thấy không có sự khác biệt. Đối với một bản in mảng nhanh bằng cách sử dụng declare -p array
sẽ trả về cho bạn các mảng mảng thực và giá trị tương ứng trong mỗi chỉ mục.
read -d'\n'
phương pháp không hiệu quả với bạn?
read -d'\n'
hoạt động tốt
Để đảo ngược một mảng tùy ý (có thể chứa bất kỳ số phần tử nào với bất kỳ giá trị nào):
Với zsh
:
array_reversed=("${(@Oa)array}")
Với bash
4.4+, do bash
các biến không thể chứa byte NUL, bạn có thể sử dụng GNU tac -s ''
trên các phần tử được in dưới dạng bản ghi phân cách NUL:
readarray -td '' array_reversed < <(
((${#array[@]})) && printf '%s\0' "${array[@]}" | tac -s '')
POSIXly, để đảo ngược mảng vỏ POSIX ( $@
, được làm bằng $1
, $2
...):
code='set --'
n=$#
while [ "$n" -gt 0 ]; do
code="$code \"\${$n}\""
n=$((n - 1))
done
eval "$code"
Giải pháp bash tinh khiết, sẽ làm việc như một lớp lót.
$: for (( i=${#array[@]}-1; i>=0; i-- ))
> do rev[${#rev[@]}]=${array[i]}
> done
$: echo "${rev[@]}"
7 6 5 4 3 2 1
rev+=( "${array[i]}" )
có vẻ đơn giản hơn.
bạn cũng có thể cân nhắc sử dụng seq
array=(1 2 3 4 5 6 7)
for i in $(seq $((${#array[@]} - 1)) -1 0); do
echo ${array[$i]}
done
trong freebsd bạn có thể bỏ qua tham số tăng -1:
for i in $(seq $((${#array[@]} - 1)) 0); do
echo ${array[$i]}
done
array=(1 2 3 4 5 6 7)
echo "${array[@]} " | tac -s ' '
Hoặc là
array=(1 2 3 4 5 6 7)
reverse=$(echo "${array[@]} " | tac -s ' ')
echo ${reverse[@]}
7 6 5 4 3 2 1
$ tac --version
tac (GNU coreutils) 8.28