Câu trả lời:
Sử dụng kết hợp tr+ tac+paste
$ tr '.' $'\n' <<< 'arg1.arg2.arg3.arg4.arg5' | tac | paste -s -d '.'
arg5.arg4.arg3.arg2.arg1Nếu bạn vẫn thích bash, bạn có thể làm theo cách này,
IFS=. read -ra line <<< "arg1.arg2.arg3.arg4."
let x=${#line[@]}-1;
while [ "$x" -ge 0 ]; do
echo -n "${line[$x]}.";
let x--;
doneSử dụng perl,
$ echo 'arg1.arg2.arg3.arg4.arg5' | perl -lne 'print join ".", reverse split/\./;'
arg5.arg4.arg3.arg2.arg1Nếu bạn không phiền một chút python:
".".join(s.split(".")[::-1])
Thí dụ:
$ python3 -c 's="arg1.arg2.arg3.arg4.arg5"; print(".".join(s.split(".")[::-1]))'
arg5.arg4.arg3.arg2.arg1
s.split(".")tạo một danh sách chứa .các chuỗi con riêng biệt, [::-1]đảo ngược danh sách và ".".join()nối các thành phần của danh sách đảo ngược với ..Bạn có thể làm điều đó với một sedlời mời duy nhất :
sed -E 'H;g;:t;s/(.*)(\n)(.*)(\.)(.*)/\1\4\5\2\3/;tt;s/\.(.*)\n/\1./'
cái này sử dụng bộ đệm giữ để có được một dòng mới hàng đầu trong không gian mẫu và sử dụng nó để hoán vị cho đến khi dòng mới không còn theo sau bởi bất kỳ dấu chấm nào tại đó nó loại bỏ dấu chấm hàng đầu khỏi không gian mẫu và thay thế dòng mới bằng dấu chấm.
Với BRE và một regex hơi khác:
sed 'H
g
:t
s/\(.*\)\(\n\)\(.*\)\(\.\)\(.*\)/\1\4\5\2\3/
tt
s/\(\.\)\(.*\)\n/\2\1/'
Nếu đầu vào bao gồm nhiều hơn một dòng và bạn muốn đảo ngược thứ tự trên mỗi dòng:
sed -E 'G;:t;s/(.*)(\.)(.*)(\n)(.*)/\1\4\5\2\3/;tt;s/(.*)\n(\.)(.*)/\3\2\1/'
Với zsh:
$ string=arg1.arg2.arg3.arg4.arg5
$ printf '%s\n' ${(j:.:)${(Oas:.:)string}}
arg5.arg4.arg3.arg2.arg1
Để bảo tồn các phần tử trống:
$ string=arg1.arg2.arg3.arg4..arg5.
$ printf '%s\n' ${(j:.:)"${(@Oas:.:)string}"}
.arg5..arg4.arg3.arg2.arg1
s:.:: tách ra .Oa: sắp xếp mảng theo chiều ngược lại một chỉ số rray o rderj:.:: Tham gia vào ..@: "$@"mở rộng giống như khi ở dấu ngoặc kép để việc mở rộng không trải qua quá trình xóa trống.bashTương đương POSIX (hoặc ) có thể là một cái gì đó như:
string=arg1.arg2.arg3.arg4..arg5.
IFS=.; set -f
set -- $string$IFS # split string into "$@" array
unset pass
for i do # reverse "$@" array
set -- "$i" ${pass+"$@"}
pass=1
done
printf '%s\n' "$*" # "$*" to join the array elements with the first
# character of $IFS
(lưu ý rằng zsh(trong shmô phỏng) yashvà một số pdkshvỏ dựa trên không phải là POSIX về mặt chúng được coi $IFSnhư một dấu tách trường thay vì dấu phân cách trường)
Trường hợp khác với một số giải pháp khác được đưa ra ở đây là nó không xử lý ký tự dòng mới (và trong trường hợp zsh, một trong số NUL), đặc biệt, nó $'ab.cd\nef.gh'sẽ bị đảo ngược $'gh.cd\nef.ab', không $'cd.ab\ngh.ef'hoặc $'gh.ef.cd.ab'.
IFS="."; set -f; set -- $string$IFS; for i; do rev="$i$IFS$rev"; done; printf '%s\n' "${rev%$IFS}"vậy?
for i; docái không phải là POSIX (chưa) ngay cả khi nó được hỗ trợ bởi tất cả các vỏ POSIX mà tôi biết). Đó chỉ là giải pháp đó là một bản dịch trực tiếp của zshmột (chia thành mảng, mảng ngược, nối các phần tử mảng) nhưng sử dụng các toán tử chỉ POSIX. (Tôi đã thay đổi string=$string$IFS; set -- $stringđến set -- $string$IFSnhư điều đó dường như làm việc nhất quán trên vỏ, nhờ).
Tôi thấy Rahul đã đăng một giải pháp bash bản địa (trong số những giải pháp khác), đây là phiên bản ngắn hơn của giải pháp đầu tiên tôi nghĩ ra:
function reversedots1() (
IFS=. read -a array <<<"$1"
new=${array[-1]}
for((i=${#array[*]} - 2; i >= 0; i--))
do
new=${new}.${array[i]}
done
printf '%s\n' "$new"
)
nhưng tôi không thể dừng lại ở đó và cảm thấy cần phải viết một giải pháp bash-centric đệ quy:
function reversedots2() {
if [[ $1 =~ ^([^.]*)\.(.*)$ ]]
then
printf %s $(reversedots2 "${BASH_REMATCH[2]}") . "${BASH_REMATCH[1]}"
else
printf %s "$1"
fi
}
Không thấy awkcâu trả lời, vì vậy đây là một câu trả lời:
echo 'arg1.arg2.arg3' | awk -F. '{for (i=NF; i>0; --i) printf "%s%s", (i<NF ? "." : ""), $i; printf "\n"}'