Indexar uma string no bash

12

Como posso me referir a uma string por índice em sh / bash? Isto é, basicamente dividindo-o.

Estou tentando remover 5 caracteres de um nome de arquivo. Todos os nomes possuem a estrutura: name_nr_code. Eu estou tentando remover o bit de código alfanumérico de 5. name_nr_ é sempre 10 caracteres.

Existe algo como:

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

    
por Pierre B 17.08.2016 / 15:32

5 respostas

10

Simples assim.

(bash)

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

Voila.

E uma explicação do Guia avançado de script de script (Capítulo 10. Manipulação de Variáveis ) , (com extra NOTA s em linha para destacar os erros nesse manual):

Substring Extraction

${string:position}

Extracts substring from $string at $position.

If the $string parameter is "*" or "@", then this extracts the positional parameters, starting at $position.

${string:position:length}

Extracts $length characters of substring from $string at $position.

NOTA falta de aspas em torno de expansões de parâmetros! echo não deve ser usado para dados arbitrários.

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.

The position and length arguments can be "parameterized," that is, represented as a variable, rather than as a numerical constant.

If the $string parameter is "*" or "@", then this extracts a maximum of $length positional parameters, starting at $position.

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

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

NOTA : expr substr é uma extensão do GNU.

expr substr $string $position $length

Extracts $length characters from $string starting at $position.

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

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

OBSERVAÇÃO : Esse echo é redundante e o torna ainda menos confiável. Use expr substr + "$string1" 1 2 .

NOTA : expr retornará com um status de saída diferente de zero se a saída for 0 (ou -0, 00 ...).

BTW. O livro está presente no repositório oficial do Ubuntu como abs-guide .

    
por 05.09.2016 / 12:36
9

No POSIX sh ,

  • "${var%?????}" is $var despojado dos últimos cinco caracteres finais (ou $var se $var contiver menos de 5 caracteres)

  • "${var%"${var#??????????}"}" são os primeiros 10 caracteres de $var .

  • "${var%_*}" is $var despojado da string mais curta que corresponde a _* no final de $var ( foo_bar_baz - > foo_bar ).
  • "${var%%_*}" : igual, mas a correspondência mais longa, em vez da correspondência mais curta ( foo_bar_baz - > foo ).
  • se você quiser obter foo_bar_ : "${var%"${var##*_}"}" ( ${var##pattern} é o mesmo que ${var%%pattern} , mas procurando o padrão no início de $var em vez do fim).

com zsh :

  • $var[1,-6] para o primeiro caractere para o 6º do final (todos, exceto os últimos 5).
  • $var[1,10] para os primeiros 10 caracteres.

Com ksh , bash ou zsh :

  • "${var:0:10}" : primeiros 10 caracteres de $var

com bash ou zsh :

  • "${var:0:-5}" : todos menos os últimos 5 caracteres (apresenta um erro e sai do script se $var estiver definido, mas contiver menos de 5 caracteres, também quando $var não estiver definido com zsh ).

Se você precisar de compatibilidade com o Bourne sh , é muito difícil fazer isso de maneira confiável. Se você puder garantir que o resultado não terminará em caracteres de nova linha, você pode fazer:

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\}''

Você também terá um limite no comprimento de $var (variando entre sistemas).

Em todas essas soluções, se $var contiver bytes que não podem fazer parte de caracteres válidos, YMMV.

    
por 17.08.2016 / 15:53
2

A maioria dos shells suporta algum tipo de expansão de parâmetro que pode ajudá-lo. No bash, você pode usar

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

Em dash , as compensações não são suportadas, mas você pode usar padrões iniciais e finais:

remove_first3=${string#???}
remove_last2=${string%??}
    
por 17.08.2016 / 15:45
1

sh não fornece uma maneira integrada de obter uma substring de uma string (até onde eu posso ver), mas com bash você pode fazer

${i:0:10}

Isso lhe dará os dez primeiros caracteres do valor da variável i .

O formato geral é ${variable:offset:length} .

    
por 17.08.2016 / 15:44
0

Primeiro, não use um loop for para nomes de arquivos.

Então, algo assim deve ajudar.

find ./ -type f | while read filename ;do
  newfilename=$(echo ${filename}|cut -c 1-10)
  mv ${filename} ${newfilename}
done
    
por 17.08.2016 / 15:42