Разделение строки, извлечение символов и соединение назад

У меня есть строки в форме wva/sia/e1, bct/e2, sv/de/e11. Это всегда <Part1>/e<NUM> или <Part1>/<Part2>/e<NUM>. То, что я хочу, должно укоротить строки путем хранения первых букв частей и отказа от наклонных черт и e:

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

Как я могу сделать ту внутреннюю часть sh сценарий?

Править: Строка представляет имя задания:

[...]
job_name=$1 # e.g. 'wva/sia/e1'
job_name=cut_name(job_name) # e.g. 'ws1'
[...]
4
задан 9 April 2017 в 02:23

3 ответа

В форме сценария как, что Вы просите:

#!/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:])

Обратите внимание, что это работает на любую длину, например:

wva/sia/bct/wva/sia/e1

станет

wsbws1

пока последний раздел заканчивается /e<num>

Использовать

  1. Скопируйте сценарий в пустой файл, сохраните его как rearrange.py
  2. Выполните его со строкой как аргумент, например:

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

Объяснение

Сценарий в значительной степени объясняется, но также и прокомментирован.

5
ответ дан 1 December 2019 в 09:03

Острота Bash 4.3

Позвольте нам просто сказать, что нам не нужен полный сценарий. Bash имеет достаточно возможностей, которые позволяют нам сходить с рук острота. Вот тот:

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

Что происходит?

  • все происходит в подоболочке, следовательно ( ) вокруг целой команды
  • мы используем здесь строку <<< отправить вход и команду подоболочки получает его через read -r var и хранилища в var переменная
  • мы устанавливаем IFS='/' так, чтобы подоболочка повредилась var в отдельные объекты в / разделитель. Это важно для разделения слова.
  • затем мы используем суффиксное удаление ${var%/*} избавиться от последней части прежде / . В вышеупомянутом примере это было бы e11
  • printf "%c" будет видеть результат ${var%/*} как sv de из-за разделения слова и суффиксного упомянутого выше удаления (волшебство, да). Из-за как printf слова, %c распечатает только первый символ, но он сделает так для каждого параметра командной строки, для которого он получает, таким образом, sv de это произведет s и d. Печать сделана без новой строки, следовательно появляется, как будто символы вводятся в последовательности
  • echo ${var##*[^0-9]} использует удаление префикса для избавлений от всех символов нецифры в данной входной строке, таким образом получая только последние цифры

Существует другой подход остроты, который является немного более явным и естественным для подобных C программистов.

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

Что это волшебно? Вот объяснение:

  • Все происходит в подоболочке, следовательно () вокруг целой команды.
  • Мы используем здесь-строку <<< для отправки объекта, мы хотим в stdin поток команды, и команда получает его через read -r inp команда и хранилища это в inp переменная
  • Затем мы изменяемся IFS переменная так, чтобы мы могли сломать все в массив.
  • мы выполняем итерации по всем объектам до того перед последним использованием C-стиля для цикла for ((initial condition; test condition; post condition)) ; do ... done
  • $(( ${#arr[@]} - 1 )) арифметическое расширение, где мы вычитаем 1 из длины массива ${#arr[@]}
  • printf "%s" ${arr[$i]:0:1} позволяет нам использовать расширение параметра, где мы печатаем только первый символ каждого объекта, и printf "%s" печать это без новой строки, таким образом это появляется как, мы печатаем каждую букву на той же строке.
  • наконец, после того как цикл закончен, мы берем исходный входной текст и избавляемся от всего, что является нецифрой с помощью удаления префикса ${#*[^0-9]}

Подход сценария

Так как вопрос просит сценарий оболочки, вот один в bash 4.3, который является почти тем же подходом как выше, но более явный:

#!/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

Путем это работает, похож так:

  • учитывая строку на командной строке как аргумент, мы устанавливаем внутреннего разделителя полей на / , и позвольте удару выполнять разделение слова для разрушения строки в названный массив items
  • мы выполняем итерации по всем объектам в массиве ${items[@]} , при отслеживании, которого объекта мы при использовании переменной счетчика и знании количества объектов в массиве ( ${#items[@]} часть).
  • if-statement то, что позволяет нам выбирать определенный символ от каждого объекта. Используя расширение параметра, первый символ через${i:0:1}. Используя самое долгое удаление префикса ${variable##prefix}, мы удаляем все символы нецифры из последней строки в printf "%s\n" "${i##*[^0-9]}".

Здесь это в действии:

$ ./shorten_string.sh "wva/sia/e1"                         
ws1
$ ./shorten_string.sh "bct/e2"                             
b2
$ ./shorten_string.sh  "sv/de/e11"                     
sd11
3
ответ дан 1 December 2019 в 09:03

Хорошо, не сценарий, но можно поместить его в сценарий (также это очень неэлегантно, так как мне не удалось иметь дело с обеими формами в одной команде),

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

Примечания

  • -r используйте ДО
  • s:old:new: замена old с new
  • .* любое количество любых символов
  • (.) сохраните один символ в этом положении
  • ([0-9]+) сохраните по крайней мере одну цифру здесь
  • ; разделяет команды, как в оболочке
  • \1 обратная ссылка на символы, сохраненные с ()
1
ответ дан 1 December 2019 в 09:03

Другие вопросы по тегам:

Похожие вопросы: