it-swarm.com.de

Saite spalten, Zeichen extrahieren und wieder zusammenfügen

Ich habe Zeichenfolgen in Form von wva/sia/e1, bct/e2, sv/de/e11. Es ist immer <Part1>/e<NUM> oder <Part1>/<Part2>/e<NUM>. Ich möchte die Saiten kürzen, indem ich die Anfangsbuchstaben der Teile behalte und die Schrägstriche und e weglasse:

wva/sia/e1 > ws1
bct/e2 > b2
sv/de/e11 > sd11

Wie kann ich das in einem sh-Skript tun?

Bearbeiten: Die Zeichenfolge repräsentiert einen Jobnamen:

[...]
job_name=$1 # e.g. 'wva/sia/e1'
job_name=cut_name(job_name) # e.g. 'ws1'
[...]
4
user1406177

In Form eines Drehbuch als das, wonach Sie fragen:

#!/usr/bin/env python3
import sys

# read the input, split by /
st = sys.argv[1].split("/")
# get the first char of all sections *but* the last one
# add the last *from* the first character
print("".join([s[0] for s in st][:-1])+st[-1][1:])

Beachten Sie, dass dies für jede Länge funktioniert, z.

wva/sia/bct/wva/sia/e1

wird werden

wsbws1

solange der letzte Abschnitt mit /e<num> endet

Benutzen

  1. Kopieren Sie das Skript in eine leere Datei und speichern Sie es als rearrange.py
  2. Führen Sie es mit der Zeichenfolge als Argument aus, z.

    python3 /path/to/rearrange.py wva/sia/e1
    
    > ws1
    

Erläuterung

Das Skript erklärt sich so ziemlich von selbst, wird aber auch kommentiert.

5
Jacob Vlijm

Bash 4.3 Einzeiler

Sagen wir einfach, wir brauchen kein komplettes Skript. Bash hat genug Fähigkeiten, um mit einem Einzeiler davonzukommen. Hier ist eins:

bash-4.3$ (read -r var ;IFS='/'; printf "%c" ${var%/*};echo ${var##*[^0-9]}) <<<  "sv/de/e11"
sd11

Was ist los ?

  • alles geschieht in einer Subshell, daher ( ) um den gesamten Befehl
  • wir verwenden hier den String <<<, um Eingaben zu senden, und der Subshell-Befehl ruft ihn über read -r var ab und speichert ihn in der Variablen var
  • wir setzen IFS='/' so, dass die Unterschale var in separate Elemente unter / separator aufteilt. Dies ist wichtig für die Wortteilung.
  • als nächstes verwenden wir die Suffix-Entfernung ${var%/*}, um den letzten Teil vor / zu entfernen. Im obigen Beispiel wäre es e11
  • printf "%c" wird das Ergebnis von ${var%/*} als sv de aufgrund der oben erwähnten Wortteilung und Suffixentfernung sehen (magisch, ja). Aufgrund der Art und Weise, wie printf Wörter, %c nur das erste Zeichen ausgeben, wird dies jedoch für jedes empfangene Befehlszeilenargument durchgeführt, und für sv de wird s und d. Der Ausdruck erfolgt ohne Zeilenvorschub, daher sieht es so aus, als ob die Zeichen nacheinander eingegeben werden
  • echo ${var##*[^0-9]} entfernt Präfixe, um alle nicht stelligen Zeichen in der angegebenen Eingabezeichenfolge zu entfernen und erhält nur die letzten Stellen

Es gibt noch einen weiteren Einzeiler-Ansatz, der für C-ähnliche Programmierer etwas expliziter und natürlicher ist.

bash-4.3$ (read -r inp;IFS='/';arr=( $inp ); for ((i=0;i<$(( ${#arr[@]} -1 ));i++));do printf "%s" ${arr[$i]:0:1};done;printf "%s\n" ${inp##*[^0-9]}) <<<  "sv/de/e11"
sd11

Was ist das für eine Magie? Hier ist eine Erklärung:

  • Alles geschieht in Subshell, daher () um den gesamten Befehl.
  • Wir verwenden here-string <<<, um das gewünschte Element in den stdin-Stream des Befehls zu senden, und der Befehl ruft es über den Befehl read -r inp ab und speichert es in der Variablen inp
  • Als nächstes ändern wir die Variable IFS, damit wir alles in ein Array aufteilen können.
  • wir iterieren über alle Elemente bis zu dem vorletzten Element, indem wir den C-Stil für die Schleife for ((initial condition; test condition; post condition)) ; do ... done verwenden.
  • die $(( ${#arr[@]} - 1 )) ist eine arithmetische Erweiterung, bei der wir 1 von der Länge des Arrays subtrahieren ${#arr[@]}
  • mit dem printf "%s" ${arr[$i]:0:1} können wir die Parametererweiterung verwenden, bei der nur das erste Zeichen jedes Elements gedruckt wird, und printf "%s" druckt es ohne Zeilenvorschub. Es sieht also so aus, als würden wir jeden Buchstaben in derselben Zeile drucken.
  • sobald die Schleife beendet ist, nehmen wir den ursprünglichen Eingabetext und entfernen alles, was keine Ziffer ist, durch Entfernen des Präfixes ${#*[^0-9]}

Script-Ansatz

Da in der Frage nach einem Shell-Skript gefragt wird, ist hier eines in bash 4.3, was fast der gleiche Ansatz wie oben ist, aber expliziter:

#!/bin/bash
IFS='/'
items=( $1 )
counter=1
for i in ${items[@]}
do
    if [ $counter -eq ${#items[@]}  ];
    then
        # note the space before -1
        printf "%s\n" "${i##*[^0-9]}"
    else
        printf "%s" "${i:0:1}"
    fi
    counter=$(($counter + 1)) 
done

So funktioniert das:

  • wenn wir eine Zeichenfolge in der Befehlszeile als Argument angeben, setzen wir das interne Feldtrennzeichen auf / und ermöglichen es der Bash, eine Word-Aufteilung durchzuführen, um die Zeichenfolge in ein Array mit dem Namen items aufzuteilen.
  • wir iterieren über alle Elemente im Array ${items[@]}, während wir verfolgen, welches Element die Zählervariable verwendet und wie viele Elemente im Array enthalten sind (der Teil ${#items[@]}).
  • Mit dem if-statement können wir für jeden Gegenstand einen bestimmten Charakter auswählen. Mit Parametererweiterung erstes Zeichen über${i:0:1}. Mit der Option zum Entfernen des längsten Präfixes ${variable##prefix} entfernen wir alle nichtstelligen Zeichen aus der letzten Zeichenfolge in printf "%s\n" "${i##*[^0-9]}".

Hier ist es in Aktion:

$ ./shorten_string.sh "wva/sia/e1"                         
ws1
$ ./shorten_string.sh "bct/e2"                             
b2
$ ./shorten_string.sh  "sv/de/e11"                     
sd11
3

OK, kein Skript, aber Sie können es in ein Skript einfügen.

$ sed -r 's:(.).*/(.).*/e([0-9]+):\1\2\3:;s:(.).*/e([0-9]+):\1\2:' file
ws1
b2
sd11

Anmerkungen

  • -r Benutze ERE
  • s:old:new:old durch new ersetzen
  • .* Beliebig viele beliebige Zeichen
  • (.) Speichert ein Zeichen an dieser Stelle
  • ([0-9]+) Hier mindestens eine Ziffer speichern
  • ; Trennt Befehle wie in der Shell
  • \1 Rückverweis auf Zeichen, die mit () Gespeichert wurden
1
Zanna