Odpowiedzi:
Używanie kombinacji tr
+ tac
+paste
$ tr '.' $'\n' <<< 'arg1.arg2.arg3.arg4.arg5' | tac | paste -s -d '.'
arg5.arg4.arg3.arg2.arg1
Jeśli nadal wolisz bash, możesz to zrobić w ten sposób,
IFS=. read -ra line <<< "arg1.arg2.arg3.arg4."
let x=${#line[@]}-1;
while [ "$x" -ge 0 ]; do
echo -n "${line[$x]}.";
let x--;
done
Za pomocą perl
,
$ echo 'arg1.arg2.arg3.arg4.arg5' | perl -lne 'print join ".", reverse split/\./;'
arg5.arg4.arg3.arg2.arg1
Jeśli nie masz nic przeciwko python
:
".".join(s.split(".")[::-1])
Przykład:
$ python3 -c 's="arg1.arg2.arg3.arg4.arg5"; print(".".join(s.split(".")[::-1]))'
arg5.arg4.arg3.arg2.arg1
s.split(".")
generuje listę zawierającą .
oddzielne podciągi, [::-1]
odwraca listę i ".".join()
łączy elementy odwróconej listy za pomocą .
.Możesz to zrobić za pomocą jednego sed
wywołania:
sed -E 'H;g;:t;s/(.*)(\n)(.*)(\.)(.*)/\1\4\5\2\3/;tt;s/\.(.*)\n/\1./'
używa to bufora wstrzymania, aby uzyskać wiodącą nową linię w przestrzeni wzorów i używa jej do przeprowadzania permutacji, dopóki po nowej linii nie będzie już żadnej kropki, w której to punkcie usuwa wiodącą kropkę z przestrzeni wzorów i zastępuje nową linię kropką.
Z BRE i nieco innym wyrażeniem regularnym:
sed 'H
g
:t
s/\(.*\)\(\n\)\(.*\)\(\.\)\(.*\)/\1\4\5\2\3/
tt
s/\(\.\)\(.*\)\n/\2\1/'
Jeśli dane wejściowe składają się z więcej niż jednej linii i chcesz odwrócić kolejność w każdej linii:
sed -E 'G;:t;s/(.*)(\.)(.*)(\n)(.*)/\1\4\5\2\3/;tt;s/(.*)\n(\.)(.*)/\3\2\1/'
Z zsh
:
$ string=arg1.arg2.arg3.arg4.arg5
$ printf '%s\n' ${(j:.:)${(Oas:.:)string}}
arg5.arg4.arg3.arg2.arg1
Aby zachować puste elementy:
$ string=arg1.arg2.arg3.arg4..arg5.
$ printf '%s\n' ${(j:.:)"${(@Oas:.:)string}"}
.arg5..arg4.arg3.arg2.arg1
s:.:
: podzielone na .
Oa
: Tablica rodzaj Reverse rray indice O rDerj:.:
: dołącz .
.@
: zrób "$@"
podobne do rozwinięcia w podwójnych cudzysłowach, aby rozszerzenie nie zostało usunięte.Odpowiednikiem POSIX (lub bash
) może być coś takiego:
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
(zauważ, że zsh
(w sh
emulacji) yash
i niektórepdksh
powłoki oparte na tym systemie nie są pod tym względem POSIX-owe, ponieważ traktują one $IFS
jako separator pól zamiast separatora pól)
Różni się od innych podanych tu rozwiązań tym, że nie traktuje specjalnie znaku nowej linii (aw przypadku zsh
NUL) specjalnie, to znaczy, że $'ab.cd\nef.gh'
byłby odwrócony na $'gh.cd\nef.ab'
, nie $'cd.ab\ngh.ef'
lub $'gh.ef.cd.ab'
.
IFS="."; set -f; set -- $string$IFS; for i; do rev="$i$IFS$rev"; done; printf '%s\n' "${rev%$IFS}"
?
for i; do
co nie jest POSIX (jeszcze), nawet jeśli jest obsługiwane przez wszystkie znane mi powłoki POSIX). Tyle tylko, że to rozwiązanie jest bezpośrednim tłumaczeniem tego zsh
(podzielone na tablicę, tablicę odwrotną, połącz elementy tablicy), ale przy użyciu operatorów tylko POSIX. (Mam zmienił string=$string$IFS; set -- $string
się set -- $string$IFS
tak, że wydaje się działać konsekwentnie w całej muszli, dzięki).
Widzę, że Rahul opublikował już natywne rozwiązanie bash (między innymi), które jest krótszą wersją pierwszego, który wymyśliłem:
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"
)
ale nie mogłem się na tym zatrzymać i poczułem potrzebę napisania rekurencyjnego rozwiązania zorientowanego na bash:
function reversedots2() {
if [[ $1 =~ ^([^.]*)\.(.*)$ ]]
then
printf %s $(reversedots2 "${BASH_REMATCH[2]}") . "${BASH_REMATCH[1]}"
else
printf %s "$1"
fi
}
Nie widziałem awk
odpowiedzi, więc oto jedna:
echo 'arg1.arg2.arg3' | awk -F. '{for (i=NF; i>0; --i) printf "%s%s", (i<NF ? "." : ""), $i; printf "\n"}'