文字列内のドット区切り要素の逆順


14

次のような入力文字列があります:

arg1.arg2.arg3.arg4.arg5

私が欲しい出力は次のとおりです。

arg5.arg4.arg3.arg2.arg1

常に5つの引数ではなく、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
Bah、Perlソリューションを投稿するつもり
でした

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:逆にソート配列A 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 1、のいずれか)に特別、$'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何もありません(for i; do私が知っているすべてのPOSIXシェルでサポートされている場合でも、POSIXではない(まだ)。その解決策は、zshPOSIXのみの演算子を使用して、ソリューションを直接変換(配列に分割、逆配列、配列要素を結合)するだけです。(私が変更したstring=$string$IFS; set -- $stringset -- $string$IFS殻、おかげで一貫働くように思われるような)。
ステファンシャゼル16

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

純粋なバッシュ、入力に後続期間が必要です:

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.