문자열에서 점으로 구분 된 요소의 역순


14

다음과 같은 입력 문자열이 있습니다.

arg1.arg2.arg3.arg4.arg5

내가 원하는 결과는 다음과 같습니다

arg5.arg4.arg3.arg2.arg1

항상 5 개의 arg는 아니지만 2에서 10 일 수 있습니다.

bash 스크립트에서 어떻게 할 수 있습니까?

답변:


22
  • tr+ tac+의 조합 사용paste

    $ tr '.' $'\n' <<< 'arg1.arg2.arg3.arg4.arg5' | tac | paste -s -d '.'
    arg5.arg4.arg3.arg2.arg1
  • 여전히 bash를 선호한다면 이런 식으로 할 수 있습니다.

    IFS=. read -ra line <<< "arg1.arg2.arg3.arg4."
    let x=${#line[@]}-1; 
    while [ "$x" -ge 0 ]; do 
          echo -n "${line[$x]}."; 
          let x--; 
    done
  • 사용하여 perl,

    $ echo 'arg1.arg2.arg3.arg4.arg5' | perl -lne 'print join ".", reverse split/\./;'
    arg5.arg4.arg3.arg2.arg1

2
바, 난 그냥 펄 솔루션을 게시하려고했습니다 :)
ilkkachu

10

조금이라도 신경 쓰지 않으면 python:

".".join(s.split(".")[::-1])

예:

$ python3 -c 's="arg1.arg2.arg3.arg4.arg5"; print(".".join(s.split(".")[::-1]))'
arg5.arg4.arg3.arg2.arg1
  • s.split(".").분리 된 하위 문자열을 포함하는 목록을 생성하고 목록을 [::-1]반전시키고 반대 목록 ".".join()의 구성 요소를로 결합합니다 ..

5

한 번의 sed호출로 수행 할 수 있습니다 .

sed -E 'H;g;:t;s/(.*)(\n)(.*)(\.)(.*)/\1\4\5\2\3/;tt;s/\.(.*)\n/\1./'

이것은 홀드 버퍼를 사용하여 패턴 공간에서 선행 개행을 가져오고 더 이상 개행 뒤에 패턴 공간에서 선행 점을 제거하고 개행을 점으로 대체하는 점이 없어 질 때까지 순열을 수행하는 데 사용합니다.
BRE와 약간 다른 정규식으로 :

sed 'H
g
:t
s/\(.*\)\(\n\)\(.*\)\(\.\)\(.*\)/\1\4\5\2\3/
tt
s/\(\.\)\(.*\)\n/\2\1/'

입력이 둘 이상의 라인으로 구성되어 있고 각 라인의 순서를 바꾸려면 :

sed -E 'G;:t;s/(.*)(\.)(.*)(\n)(.*)/\1\4\5\2\3/;tt;s/(.*)\n(\.)(.*)/\3\2\1/'

3

SED 솔루션 :

sed 's/\./\n/g' yourFile | tac | sed ':a; $!{N;ba};s/\n/./g'

3

zsh:

$ string=arg1.arg2.arg3.arg4.arg5
$ printf '%s\n' ${(j:.:)${(Oas:.:)string}}
arg5.arg4.arg3.arg2.arg1

빈 요소를 유지하려면

$ string=arg1.arg2.arg3.arg4..arg5.
$ printf '%s\n' ${(j:.:)"${(@Oas:.:)string}"}
.arg5..arg4.arg3.arg2.arg1
  • s:.:: 분할 .
  • Oa: 반대로 정렬 배열 rray indice O RDER
  • j:.::에 가입하십시오 ..
  • @: "$@"큰 따옴표로 묶었을 때처럼 확장을 수행 하므로 확장이 비어 있지 않습니다.

POSIX (또는 bash)는 다음과 같습니다.

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

(참고 zsh(에서 sh) 에뮬레이션, yash일부 pdksh기반 껍질하지 POSIX은 치료 점에서 그 점에$IFS 대신 필드 구분 기호의 필드 구분자로)

그것은 여기에 주어진 다른 솔루션의 일부는 다른 경우가 개행 문자를 취급하지 않는다는 것입니다 (그리고의 경우 zsh중 하나 NUL의 하나) 특별히, 즉 $'ab.cd\nef.gh'로 반전 될 것이다 $'gh.cd\nef.ab',하지 $'cd.ab\ngh.ef'$'gh.ef.cd.ab'.


무슨 일이야 IFS="."; set -f; set -- $string$IFS; for i; do rev="$i$IFS$rev"; done; printf '%s\n' "${rev%$IFS}"?

@BinaryZebra Nothing (아마도 for i; do내가 알고있는 모든 POSIX 셸에서 지원하더라도 POSIX (아직)는 아닙니다). 그 솔루션은 zshPOSIX 전용 연산자를 사용 하는 것 (배열, 역 배열, 조인 배열 요소로 분할 )의 직접 변환입니다 . (나는 셸에서 일관되게 작동하는 것처럼 to string=$string$IFS; set -- $string을 변경했습니다 set -- $string$IFS. 감사합니다).
Stéphane Chazelas

2

Rahul은 이미 네이티브 bash 솔루션을 게시 한 것을 보았습니다.이 솔루션은 내가 처음으로 생각해 낸 짧은 버전입니다.

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"
)

그러나 나는 거기서 멈출 수 없었고 재귀 bash 중심 솔루션을 작성할 필요성을 느꼈습니다.

function reversedots2() {
  if [[ $1 =~ ^([^.]*)\.(.*)$ ]]
  then
    printf %s $(reversedots2 "${BASH_REMATCH[2]}") . "${BASH_REMATCH[1]}"
  else
    printf %s "$1"
  fi
}

2

awk답을 보지 못 했으므로 여기에 하나가 있습니다.

 echo 'arg1.arg2.arg3' | awk -F. '{for (i=NF; i>0; --i) printf "%s%s", (i<NF ? "." : ""), $i; printf "\n"}'

1

Pure Bash, 입력시 후행 기간이 필요합니다.

echo 'foo.bar.baz.' | ( while read -d . f;do g="$f${g+.}$g" ;done;echo "$g" )

printf %s "$g"점선으로 된 요소가 하이픈으로 시작할 수있는 경우 사용하십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.