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

У меня есть строки в виде 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

16 ответов

В форме скрипта вы запрашиваете:

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

станет [!d3 ]

wsbws1

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

Использование

Скопируйте сценарий в пустой файл, сохраните его как rearrange.py Запустите его с строкой в ​​качестве аргумента, например:
python3 /path/to/rearrange.py wva/sia/e1

> ws1

Объяснение

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

5
ответ дан 22 May 2018 в 23:53
  • 1
    Я думал сделать это в bash, но я также могу просто назвать этот скрипт python. Благодаря! – user1406177 8 April 2017 в 00:16
  • 2
    @ user1406177 добро пожаловать! Не уверен, что bash - самый удобный инструмент для этого :) – Jacob Vlijm 8 April 2017 в 00:17
  • 3
    Ну, баш тоже может это сделать :) – Sergiy Kolodyazhnyy 8 April 2017 в 01:09

В форме скрипта вы запрашиваете:

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

Использование

Скопируйте сценарий в пустой файл, сохраните его как rearrange.py Запустите его с строкой в ​​качестве аргумента, например: python3 /path/to/rearrange.py wva/sia/e1 > ws1

Объяснение

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

5
ответ дан 18 July 2018 в 15:21

В форме скрипта вы запрашиваете:

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

Использование

Скопируйте сценарий в пустой файл, сохраните его как rearrange.py Запустите его с строкой в ​​качестве аргумента, например: python3 /path/to/rearrange.py wva/sia/e1 > ws1

Объяснение

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

5
ответ дан 24 July 2018 в 20:37

В форме скрипта вы запрашиваете:

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

Использование

Скопируйте сценарий в пустой файл, сохраните его как rearrange.py Запустите его с строкой в ​​качестве аргумента, например: python3 /path/to/rearrange.py wva/sia/e1 > ws1

Объяснение

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

5
ответ дан 31 July 2018 в 12:44

В форме скрипта вы запрашиваете:

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

Использование

Скопируйте сценарий в пустой файл, сохраните его как rearrange.py Запустите его с строкой в ​​качестве аргумента, например: python3 /path/to/rearrange.py wva/sia/e1 > ws1

Объяснение

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

5
ответ дан 31 July 2018 в 23:38

В виде скрипта , как вы просите:

#!/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
ответ дан 5 August 2018 в 05:33

Bash 4.3 One-liner

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

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

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

все происходит в подоболочке, поэтому ( ) вокруг всей команды мы используем здесь строку <<< для отправки ввода, а Команда subshell получает его через 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

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

все происходит в подоболочке, поэтому ( ) вокруг всей команды Мы используем здесь-string <<< для отправки элемента, который мы хотим, в поток stdin команды, и команда получает его через команду read -r inp и сохраняет ее в переменной inp , мы используем здесь строку <<< для отправки ввода, а команда subshell получает ее через read -r var и сохраняет в var переменную [ ! d5] мы перебираем все элементы до последнего, используя C-стиль для цикла for ((initial condition; test condition; post condition)) ; do ... done , мы устанавливаем IFS='/', чтобы подоболочка разбивала var на отдельные элементы в разделителе /. Это важно для разбиения слов. printf "%s" ${arr[$i]:0:1} позволяет нам использовать расширение параметра, где мы печатаем только первый символ каждого элемента, а printf "%s" печатает его без символа новой строки, поэтому он выглядит так, как будто мы печатаем каждую букву на той же линии. Далее мы используем удаление суффиксов ${var%/*}, чтобы избавиться от последней части до /. В приведенном выше примере это будет e11

Сценарий

Поскольку вопрос задает сценарий оболочки, вот один из 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

Как это работает, так:

Мы используем здесь-строку <<< для отправки элемент, который мы хотим в потоке stdin команды, и команда получает его через команду read -r inp и сохраняет его в переменной inp , мы перебираем все элементы в массиве ${items[@]}, сохраняя при этом отслеживание того, re при использовании переменной счетчика и знании количества элементов в массиве (часть ${#items[@]}). мы перебираем все элементы до последнего, используя C-стиль для цикла for ((initial condition; test condition; post condition)) ; do ... done

Здесь он находится в действии:

$ ./shorten_string.sh "wva/sia/e1"                         
ws1
$ ./shorten_string.sh "bct/e2"                             
b2
$ ./shorten_string.sh  "sv/de/e11"                     
sd11
3
ответ дан 22 May 2018 в 23:53

ОК, а не сценарий, но вы можете поместить его в скрипт (также это очень неэлегантно, так как я не справился с обеими формами в одной команде)

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

Примечания

-r использовать ERE s:old:new: заменить old на new .* любое количество любых символов (.) сохранить один символ в этом положении ([0-9]+) сохранить хотя бы одну цифру здесь ; отделяет команды , как в командной строке \1 для символов, сохраненных с помощью ()
1
ответ дан 22 May 2018 в 23:53

Bash 4.3 One-liner

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

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

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

все происходит в подоболочке, поэтому ( ) вокруг всей команды мы используем здесь строку <<< для отправки ввода, а Команда subshell получает его через 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

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

все происходит в подоболочке, поэтому ( ) вокруг всей команды Мы используем здесь-string <<< для отправки элемента, который мы хотим, в поток stdin команды, и команда получает его через команду read -r inp и сохраняет ее в переменной inp , мы используем здесь строку <<< для отправки ввода, а команда subshell получает ее через read -r var и сохраняет в var переменную [ ! d5] мы перебираем все элементы до последнего, используя C-стиль для цикла for ((initial condition; test condition; post condition)) ; do ... done , мы устанавливаем IFS='/', чтобы подоболочка разбивала var на отдельные элементы в разделителе /. Это важно для разбиения слов. printf "%s" ${arr[$i]:0:1} позволяет нам использовать расширение параметра, где мы печатаем только первый символ каждого элемента, а printf "%s" печатает его без символа новой строки, поэтому он выглядит так, как будто мы печатаем каждую букву на той же линии. Далее мы используем удаление суффиксов ${var%/*}, чтобы избавиться от последней части до /. В приведенном выше примере это будет e11

Сценарий

Поскольку вопрос задает сценарий оболочки, вот один из 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

Как это работает, так:

Мы используем здесь-строку <<< для отправки элемент, который мы хотим в потоке stdin команды, и команда получает его через команду read -r inp и сохраняет его в переменной inp , мы перебираем все элементы в массиве ${items[@]}, сохраняя при этом отслеживание того, re при использовании переменной счетчика и знании количества элементов в массиве (часть ${#items[@]}). мы перебираем все элементы до последнего, используя C-стиль для цикла for ((initial condition; test condition; post condition)) ; do ... done

Здесь он находится в действии:

$ ./shorten_string.sh "wva/sia/e1" ws1 $ ./shorten_string.sh "bct/e2" b2 $ ./shorten_string.sh "sv/de/e11" sd11
3
ответ дан 18 July 2018 в 15:21

ОК, а не сценарий, но вы можете поместить его в скрипт (также это очень неэлегантно, так как я не справился с обеими формами в одной команде)

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

Примечания

-r использовать ERE s:old:new: заменить old на new .* любое количество любых символов (.) сохранить один символ в этом положении ([0-9]+) сохранить хотя бы одну цифру здесь ; отделяет команды , как в командной строке \1 для символов, сохраненных с помощью ()
1
ответ дан 18 July 2018 в 15:21

Bash 4.3 One-liner

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

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

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

все происходит в подоболочке, поэтому ( ) вокруг всей команды мы используем здесь строку <<< для отправки ввода, а Команда subshell получает его через 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

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

все происходит в подоболочке, поэтому ( ) вокруг всей команды Мы используем здесь-string <<< для отправки элемента, который мы хотим, в поток stdin команды, и команда получает его через команду read -r inp и сохраняет ее в переменной inp , мы используем здесь строку <<< для отправки ввода, а команда subshell получает ее через read -r var и сохраняет в var переменную [ ! d5] мы перебираем все элементы до последнего, используя C-стиль для цикла for ((initial condition; test condition; post condition)) ; do ... done , мы устанавливаем IFS='/', чтобы подоболочка разбивала var на отдельные элементы в разделителе /. Это важно для разбиения слов. printf "%s" ${arr[$i]:0:1} позволяет нам использовать расширение параметра, где мы печатаем только первый символ каждого элемента, а printf "%s" печатает его без символа новой строки, поэтому он выглядит так, как будто мы печатаем каждую букву на той же линии. Далее мы используем удаление суффиксов ${var%/*}, чтобы избавиться от последней части до /. В приведенном выше примере это будет e11

Сценарий

Поскольку вопрос задает сценарий оболочки, вот один из 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

Как это работает, так:

Мы используем здесь-строку <<< для отправки элемент, который мы хотим в потоке stdin команды, и команда получает его через команду read -r inp и сохраняет его в переменной inp , мы перебираем все элементы в массиве ${items[@]}, сохраняя при этом отслеживание того, re при использовании переменной счетчика и знании количества элементов в массиве (часть ${#items[@]}). мы перебираем все элементы до последнего, используя C-стиль для цикла for ((initial condition; test condition; post condition)) ; do ... done

Здесь он находится в действии:

$ ./shorten_string.sh "wva/sia/e1" ws1 $ ./shorten_string.sh "bct/e2" b2 $ ./shorten_string.sh "sv/de/e11" sd11
3
ответ дан 24 July 2018 в 20:37

ОК, а не сценарий, но вы можете поместить его в скрипт (также это очень неэлегантно, так как я не справился с обеими формами в одной команде)

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

Примечания

-r использовать ERE s:old:new: заменить old на new .* любое количество любых символов (.) сохранить один символ в этом положении ([0-9]+) сохранить хотя бы одну цифру здесь ; отделяет команды , как в командной строке \1 для символов, сохраненных с помощью ()
1
ответ дан 24 July 2018 в 20:37

Bash 4.3 One-liner

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

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

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

все происходит в подоболочке, поэтому ( ) вокруг всей команды мы используем здесь строку <<< для отправки ввода, а Команда subshell получает его через 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

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

все происходит в подоболочке, поэтому ( ) вокруг всей команды Мы используем здесь-string <<< для отправки элемента, который мы хотим, в поток stdin команды, и команда получает его через команду read -r inp и сохраняет ее в переменной inp , мы используем здесь строку <<< для отправки ввода, а команда subshell получает ее через read -r var и сохраняет в var переменную [ ! d5] мы перебираем все элементы до последнего, используя C-стиль для цикла for ((initial condition; test condition; post condition)) ; do ... done , мы устанавливаем IFS='/', чтобы подоболочка разбивала var на отдельные элементы в разделителе /. Это важно для разбиения слов. printf "%s" ${arr[$i]:0:1} позволяет нам использовать расширение параметра, где мы печатаем только первый символ каждого элемента, а printf "%s" печатает его без символа новой строки, поэтому он выглядит так, как будто мы печатаем каждую букву на той же линии. Далее мы используем удаление суффиксов ${var%/*}, чтобы избавиться от последней части до /. В приведенном выше примере это будет e11

Сценарий [

]

Поскольку вопрос задает сценарий оболочки, вот один из 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

Как это работает, так:

Мы используем здесь-строку <<< для отправки элемент, который мы хотим в потоке stdin команды, и команда получает его через команду read -r inp и сохраняет его в переменной inp , мы перебираем все элементы в массиве ${items[@]}, сохраняя при этом отслеживание того, re при использовании переменной счетчика и знании количества элементов в массиве (часть ${#items[@]}). мы перебираем все элементы до последнего, используя C-стиль для цикла for ((initial condition; test condition; post condition)) ; do ... done

Здесь он находится в действии:

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

3
ответ дан 31 July 2018 в 12:44

ОК, а не сценарий, но вы можете поместить его в скрипт (также это очень неэлегантно, так как я не справился с обеими формами в одной команде)

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

Примечания

-r использовать ERE s:old:new: заменить old на new .* любое количество любых символов (.) сохранить один символ в этом положении ([0-9]+) сохранить хотя бы одну цифру здесь ; отделяет команды , как в командной строке \1 для символов, сохраненных с помощью ()
1
ответ дан 31 July 2018 в 12:44

Bash 4.3 One-liner

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

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

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

все происходит в подоболочке, поэтому ( ) вокруг всей команды мы используем здесь строку <<< для отправки ввода, а Команда subshell получает его через 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

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

все происходит в подоболочке, поэтому ( ) вокруг всей команды Мы используем здесь-string <<< для отправки элемента, который мы хотим, в поток stdin команды, и команда получает его через команду read -r inp и сохраняет ее в переменной inp , мы используем здесь строку <<< для отправки ввода, а команда subshell получает ее через read -r var и сохраняет в var переменную [ ! d5] мы перебираем все элементы до последнего, используя C-стиль для цикла for ((initial condition; test condition; post condition)) ; do ... done , мы устанавливаем IFS='/', чтобы подоболочка разбивала var на отдельные элементы в разделителе /. Это важно для разбиения слов. printf "%s" ${arr[$i]:0:1} позволяет нам использовать расширение параметра, где мы печатаем только первый символ каждого элемента, а printf "%s" печатает его без символа новой строки, поэтому он выглядит так, как будто мы печатаем каждую букву на той же линии. Далее мы используем удаление суффиксов ${var%/*}, чтобы избавиться от последней части до /. В приведенном выше примере это будет e11

Сценарий

Поскольку вопрос задает сценарий оболочки, вот один из 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

Как это работает, так:

Мы используем здесь-строку <<< для отправки элемент, который мы хотим в потоке stdin команды, и команда получает его через команду read -r inp и сохраняет его в переменной inp , мы перебираем все элементы в массиве ${items[@]}, сохраняя при этом отслеживание того, re при использовании переменной счетчика и знании количества элементов в массиве (часть ${#items[@]}). мы перебираем все элементы до последнего, используя C-стиль для цикла for ((initial condition; test condition; post condition)) ; do ... done

Здесь он находится в действии:

$ ./shorten_string.sh "wva/sia/e1" ws1 $ ./shorten_string.sh "bct/e2" b2 $ ./shorten_string.sh "sv/de/e11" sd11
3
ответ дан 31 July 2018 в 23:38

ОК, а не сценарий, но вы можете поместить его в скрипт (также это очень неэлегантно, так как я не справился с обеими формами в одной команде)

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

Примечания

-r использовать ERE s:old:new: заменить old на new .* любое количество любых символов (.) сохранить один символ в этом положении ([0-9]+) сохранить хотя бы одну цифру здесь ; отделяет команды , как в командной строке \1 для символов, сохраненных с помощью ()
1
ответ дан 31 July 2018 в 23:38

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

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