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.arg1
Nế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--;
done
Sử dụng perl
,
$ echo 'arg1.arg2.arg3.arg4.arg5' | perl -lne 'print join ".", reverse split/\./;'
arg5.arg4.arg3.arg2.arg1
Nế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 sed
lờ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.bash
Tươ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 sh
mô phỏng) yash
và một số pdksh
vỏ dựa trên không phải là POSIX về mặt chúng được coi $IFS
như 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; do
cá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 zsh
mộ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$IFS
như đ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 awk
câ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"}'