Индексировать строку в bash

14

Как я могу ссылаться на строку по индексу в sh / bash? То есть, в основном, это разделение.

Я пытаюсь удалить 5 символов имени файла. Все имена имеют структуру: name_nr_code. Я пытаюсь удалить 5 буквенно-цифровой кодовый бит. name_nr_всегда 10 символов.

Есть ли вещь, как;

for i in * ; do mv "$i" "$i"[:10] ; done

Пьер Б
источник
5
Зачем bashтэг, если вы спрашиваете shрешение?
Стефан Шазелас

Ответы:

14

Просто как это.

(Баш)

for i in * ; do mv -- "$i" "${i:0:5}" ; done

Вуаля.

И объяснение из Advanced Bash-Scripting Guide ( Глава 10. Управление переменными ) (с дополнительными NOTEs встроенными, чтобы выделить ошибки в этом руководстве):

Извлечение подстроки

${string:position}

Извлекает подстроку из $stringat $position.

Если $stringпараметр "*" или "@", то это извлекает позиционные параметры, начиная с $position.

${string:position:length}

Извлекает $lengthсимволы подстроки из $stringat $position.

NOTEпропущенные кавычки вокруг расширений параметров! echoне должен использоваться для произвольных данных.

stringZ=abcABC123ABCabc
#       0123456789.....
#       0-based indexing.

echo ${stringZ:0}                       # abcABC123ABCabc
echo ${stringZ:1}                       # bcABC123ABCabc
echo ${stringZ:7}                       # 23ABCabc 

echo ${stringZ:7:3}                     # 23A
                                        # Three characters of substring.


# Is it possible to index from the right end of the string?

echo ${stringZ:-4}                      # abcABC123ABCabc
# Defaults to full string, as in ${parameter:-default}.
# However . . . 

echo ${stringZ:(-4)}                    # Cabc
echo ${stringZ: -4}                     # Cabc
# Now, it works.
# Parentheses or added space "escape" the position parameter.

В позиции и длины аргументы могут быть «параметрироваться» , то есть, представлены в качестве переменной, а не в качестве числовой константы.


Если $stringпараметр "*" или "@", то это извлекает максимум $lengthпозиционных параметров, начиная с $position.

echo ${*:2}          # Echoes second and following positional parameters.
echo ${@:2}          # Same as above.

echo ${*:2:3}        # Echoes three positional parameters, starting at second.

NOTE: expr substrрасширение GNU.

expr substr $string $position $length

Извлекает $lengthсимволы из $stringначала $position.

stringZ=abcABC123ABCabc
#       123456789......
#       1-based indexing.

echo `expr substr $stringZ 1 2`           # ab
echo `expr substr $stringZ 4 3`           # ABC

NOTEЭто echoизбыточно и делает его еще менее надежным. Использование expr substr + "$string1" 1 2.

NOTE: exprвернется с ненулевым состоянием выхода, если выход равен 0 (или -0, 00 ...).


КСТАТИ. Книга присутствует в официальном репозитории Ubuntu as abs-guide.

томас
источник
Сказать «позиция» немного вводит в заблуждение, поскольку на самом деле это смещение, что означает, что значение ${var:1}не возвращается varиз «1-й позиции», а фактически из 2-й.
Кусалананда
Это правда, но пока вы не согласны, может быть нулевая позиция. Что хорошо со мной.
9

В POSIX sh,

  • "${var%?????}"будет $varлишен последних 5 символов хвостовых (или , $varесли $varсодержит менее 5 символов)

  • "${var%"${var#??????????}"}"это первые 10 символов $var.

  • "${var%_*}"будет $varлишен самой короткой строки , которая соответствует _*в конце $var( foo_bar_baz-> foo_bar).
  • "${var%%_*}": то же самое, но самое длинное совпадение вместо самого короткого ( foo_bar_baz-> foo).
  • если вы хотите получить foo_bar_: "${var%"${var##*_}"}"( ${var##pattern}то же самое, ${var%%pattern}но искать шаблон в начале, $varа не в конце).

С zsh:

  • $var[1,-6] для первого символа до 6-го от конца (так что все, кроме последних 5).
  • $var[1,10] для первых 10 символов.

С ksh, bashили zsh:

  • "${var:0:10}": первые 10 символов $var

С bashили zsh:

  • "${var:0:-5}": все, кроме последних 5 символов (выдает ошибку и выходит из сценария, если $varон задан, но содержит менее 5 символов, также если $varон не установлен с помощью zsh).

Если вам нужна shсовместимость с Bourne , это очень сложно сделать надежно. Если вы можете гарантировать, что результат не будет заканчиваться символами новой строки, вы можете сделать:

first_10=`expr " $var" : ' \(.{1,10\}\)'` # beware the exit status
                                          # may be non-zero if the
                                          # result is 0 or 0000000000

all_but_last_5=`expr " $var" : ' \(.*\).\{5\}'`

У вас также будет ограничение на длину $var(в зависимости от системы).

Во всех этих решениях, если они $varсодержат байты, которые не могут входить в состав допустимых символов, YMMV.

Стефан Шазелас
источник
Боже, они действительно придумали какой-то уродливый синтаксис для этих скобок.
кот
2

shне предоставляет встроенный способ получения подстроки из строки (насколько я вижу), но с bashвами может сделать

${i:0:10}

Это даст вам первые десять символов значения переменной i.

Общий формат есть ${variable:offset:length}.

Кусалананда
источник
2

Большинство оболочек поддерживают какое-то расширение параметров, которое может вам помочь. В Bash вы можете использовать

substr=${string:4:5} # start at position 4, length 5.

В dash, смещения не поддерживаются, но вы можете использовать начальные и конечные шаблоны:

remove_first3=${string#???}
remove_last2=${string%??}
choroba
источник
0

Во-первых, не используйте forцикл для имен файлов.

Тогда что-то вроде этого должно помочь.

find ./ -type f | while read filename ;do
  newfilename=$(echo ${filename}|cut -c 1-10)
  mv ${filename} ${newfilename}
done
MelBurslan
источник
3
Почему плохо использовать forс именами файлов?
Чороба
Цитируйте свои переменные и используйте, printfчтобы быть более безопасным. ... и read -r.
Кусалананда
3
Цикл ОП forбыл в порядке, за исключением, может быть, пропавших без вести --. Я вижу как минимум 10 ошибок в ваших 4 строках кода! многие из которых хорошо известны как плохая практика, например, предположить, что имена файлов - одна строка, использовать эхо, пропущенные кавычки
Стефан Шазелас