Delimitador na divisão de palavras

2

No Bash, a divisão de palavras é uma etapa no processamento da linha de comando. Do manual de bash

The shell treats each character of $IFS as a delimiter, and splits the results of the other expansions into words using these characters as field terminators. If IFS is unset, or its value is exactly <space><tab><newline>, the default, then sequences of <space>, <tab>, and <newline> at the beginning and end of the results of the previous expansions are ignored, and any sequence of IFS characters not at the beginning or end serves to delimit words. If IFS has a value other than the default, then sequences of the whitespace characters space and tab are ignored at the beginning and end of the word, as long as the whitespace character is in the value of IFS (an IFS whitespace character). Any character in IFS that is not IFS whitespace, along with any adjacent IFS whitespace characters, delimits a field. A sequence of IFS whitespace characters is also treated as a delimiter. If the value of IFS is null, no word splitting occurs.

Eu quero reescrever o exemplo a seguir, para que o delimitador space entre os argumentos a , b e c seja substituído por tab ou newline

$ echo a b c
a b c

Mas quando eu clico na tecla Tab , não há resposta.

Quando eu clico em \ e return , não há espaço entre a , b e c na saída:

$ echo a\
> b\
> c
abc

Por que não posso fazer o que a citação diz?

Btw, nada sai de $IFS :

$ echo $IFS
    
por Tim 28.04.2016 / 18:19

3 respostas

4

As novas linhas são tratadas especialmente por bash , independentemente do valor de IFS . Uma barra invertida antes de uma nova linha faz com que a nova linha seja ignorada . Não tem nada a ver com a divisão de palavras e ocorreria mesmo se IFS fosse definido para algum valor personalizado.

De LESS=+/^QUOTING man bash :

   A  non-quoted  backslash (\) is the escape character.  It preserves the
   literal value of the next character that follows, with the exception of
   <newline>.   If  a  \<newline>  pair  appears, and the backslash is not
   itself quoted, the \<newline> is treated as a line  continuation  (that
   is, it is removed from the input stream and effectively ignored).

Você pode ver a divisão de palavras na nova linha ocorrer de outra forma: colocando uma nova linha em uma variável e, em seguida, echo ing a variável sem citá-la.

$ myvar=a$'\n'b$'\n'c
$ echo "$myvar"
a
b
c
$ echo $myvar
a b c
$ 
    
por 28.04.2016 / 20:37
2

Resposta direta

O comando sem aspas : echo a b c , será dividido em (espaço do metacaractere) não importa o que IFS seja ou não. Os argumentos divididos para echo : a , b e c serão impressos com espaços porque echo é definido assim:

LESS=+/'^ *echo \[-neE\] \[arg ...\]' man bash

Output the args, separated by spaces, followed by a newline.

Também não há $IFS envolvido.

Então, o que você citou não tem relevância aqui. A parte principal é:

... splits the results of the other expansions into words ...

Você deve ter uma expansão antes que $IFS seja usado.
Não há expansão em a b c .

Se você tiver um efeito de $ IFS, use uma expansão sem aspas:

$ var='a   b   c'
$ echo $var
a b c

Mas isso ainda não usa $IFS para saída, apenas para divisão.

IFS na saída.

Onde $IFS tem relevância (para saída) está em $* .

$ set -- a b c
$ IFS=$'\t'
$ printf '%s\n' "$*" | od -An -vtx1c
  61  09  62  09  63  0a
   a  \t   b  \t   c  \n

É disso que você precisa?

Outras questões.

Guia do teclado

when I hit the key Tab, there is no response

Em seguida, pressione Ctrl V , solte e depois pressione Tab .

Mas sem aspas, você não poderá atribuir uma guia a uma variável. Teste:

$ var=a    b                  ### The space represents a tab as above.
bash: b: command not found

Você precisará:

$ var="a   b"                 ### The space represents a tab as above.

Aspas duplas no mínimo.

Citar o IFS

nothing comes out of $IFS:

$ echo $IFS

Nada sai do $IFS porque você não citou $IFS . Experimente:

<user>$ echo "$IFS" | sed -n l
 \t$
$
<user>$

Que tem uma nova linha de $IFS e uma do comando echo.
Melhor mudar para printf:

<user>$ printf '%s' "$IFS" | sed -n l
 \t$
<user>$

E use od:

$ printf '%s' "$IFS" | od -An -vtx1c
  20  09  0a
      \t  \n

Como já temos uma maneira de "ver" quais caracteres estão contidos em uma string.
Podemos também usar isso para "ver" o que está dentro de algumas strings:

$ var='a b c'
$ echo "$var" | od -An -vtx1c
  61  20  62  20  63  0a
   a       b       c  \n

Isso não deveria ser uma surpresa. Como isso (com aspas simples) não deve ser:

$ var='a\
> b\
> c'
$ echo "$var" | od -An -vtx1c
  61  5c  0a  62  5c  0a  63  0a
   a   \  \n   b   \  \n   c  \n

Exatamente o que foi digitado. Se a var for citada corretamente, a contrabarra aparecerá corretamente.

Citação

Mas a citação com aspas duplas pode alterar alguns caracteres:

$ var="a\
> b\
> c"
$ echo "$var" | od -An -vtx1c
  61  62  63  0a
   a   b   c  \n

Mas o que você escreveu não tem citações para definir o var nem usá-lo no echo.
Essa é uma regra de não-não em shells. Por favor Cite corretamente .

    
por 29.04.2016 / 05:18
0

Para substituir um espaço por um caractere de tabulação usando $IFS , você pode usar o argumento array:

unset IFS
set a b c
IFS=$(printf \t)
printf "%s\n" "$*"

Entenda que $IFS é sobre divisão - ele contém uma lista de caracteres que o shell usa para dividir expansões sem aspas em contextos de lista. Você não pode realmente usá-lo para substituir caracteres, exceto no caso especial do parâmetro de shell $* special. Em todos os outros casos, o seu uso será nulo imitando e delimitando certas partes de expansões de shell sem aspas.

    
por 28.04.2016 / 20:50

Tags