É um UUOC (uso inútil de cat) para redirecionar um arquivo para outro?

36

Se eu quiser fazer com que o conteúdo de file2 corresponda ao conteúdo de file1 , eu poderia obviamente executar cp file1 file2 .

No entanto, se eu quiser preservar tudo sobre file2 exceto o conteúdo - proprietário, permissões, atributos estendidos, ACLs, hard links, etc., etc. , então eu não gostaria de executar cp . * Nesse caso, eu só quero plop o conteúdo de file1 em file2 .

Parece que o seguinte faria:

< file1 > file2

Mas isso não funciona. file2 é truncado para nada e não gravado em. No entanto,

cat < file1 > file2

funciona .

Surpreendeu-me que a primeira versão não funcione.

A segunda versão é um UUOC? Existe uma maneira de fazer isso sem invocar um comando, apenas usando redirecionamentos?

Nota: Estou ciente de que o UUOC é mais um ponto pedante do que um verdadeiro antipadrão.

* Como tniles09 descoberto , cp será de fato trabalho neste caso.

    
por Wildcard 16.12.2015 / 20:58

7 respostas

57

cat < file1 > file2 não é um UUOC. Classicamente, < e > do redirecionamentos correspondem às duplicações do descritor de arquivo no nível do sistema. As duplicações do descritor de arquivo por si só não fazem nada (bem, > de redirecionamentos abrem com O_TRUNC , portanto, para ser preciso, os redirecionamentos de saída truncam o arquivo de saída). Não deixe os símbolos < > confundirem você. Redirecionamentos não movem dados - eles atribuem descritores de arquivos a outros descritores de arquivos.

Nesse caso, abra file1 e atribua esse descritor de arquivo ao descritor de arquivo 0 ( <file1 == 0<file1 ) e file2 e atribua esse descritor de arquivo ao descritor de arquivo 1 ( >file2 == 1>file2 ).

Agora que você tem dois descritores de arquivo, você precisa de um processo para remover dados entre os dois e é para isso que o cat serve.

    
por 16.12.2015 / 21:05
16

Não é, porque, como outros apontaram, o comportamento em questão é dependente do shell. Como você (o OP) apontou, isso é um pouco pedante , talvez até mesmo bem-humorado? , tipo de assunto.

No entanto, nos sistemas GNU, sua premissa inicial tem outra solução disponível: cp --no-preserve=all file1 file2 . Tente isso, acho que ele satisfará sua situação descrita (por exemplo, modificar o conteúdo de file2 sem modificar seus atributos).

Exemplo :

$ ls -l
    total 8
    -rw-r--r-- 1 tniles sambashare 16 Dec 16 12:21 fezzik
    -rw-r--r-- 1 tniles tniles     14 Dec 16 12:16 fred
$ cat *
    Lookout, world!
    Hello, world!
$ cp --no-preserve=all fred fezzik 
$ ls -l
    total 8
    -rw-r--r-- 1 tniles sambashare 14 Dec 16 12:22 fezzik
    -rw-r--r-- 1 tniles tniles     14 Dec 16 12:16 fred
$ cat *
    Hello, world!
    Hello, world!

UPDATE Na verdade, observei que o cp do meu sistema aparentemente preserva atributos, a menos que -a ou -p sejam especificados. Estou usando o bash shell e o GNU coreutils. Eu acho que você aprende algo novo todos os dias ...

Resultados do teste (por curinga), incluindo link físico e permissões diferentes:

$ ls -li
total 12
913966 -rw-rw-r-- 1 vagrant vagrant 30 Dec 16 20:26 file1
913965 -rwxrw---- 2 pete    vagrant 39 Dec 16 20:35 file2
913965 -rwxrw---- 2 pete    vagrant 39 Dec 16 20:35 hardlinktofile2
$ cat file1
This is the contents of file1
$ cat file2
This is the original contents of file2
$ cp file1 file2
$ ls -li
total 12
913966 -rw-rw-r-- 1 vagrant vagrant 30 Dec 16 20:26 file1
913965 -rwxrw---- 2 pete    vagrant 30 Dec 16 20:37 file2
913965 -rwxrw---- 2 pete    vagrant 30 Dec 16 20:37 hardlinktofile2
$ cat file1
This is the contents of file1
$ cat file2
This is the contents of file1
$ 
    
por 16.12.2015 / 21:20
13

Em zsh , o shell em que < file1 > file2 funciona, o shell invoca cat .

Para uma linha de comando que consiste apenas em redirecionamentos e nenhum comando nem atribuições, zsh invoca $NULLCMD ( cat por padrão), a menos que o único redirecionamento seja um < , caso em que $READNULLCMD ( pager por padrão) é invocado. (isto é, a menos que zsh esteja em sh ou csh emulação, caso em que se comporta como os shells que ele emula).

Então:

< file1 > file2

é na verdade o mesmo que

cat < file1 > file2

e

< file1

é o mesmo que

pager < file1
    
por 17.12.2015 / 01:19
8
< from > to

não funciona porque não há comando lá; nenhum processo. O shell abre / cria os arquivos e organiza os redirecionamentos (o que significa que os descritores de arquivos que fazem referência a esses arquivos são plantados como 0 e 1: entrada padrão e saída padrão). Mas não há nada lá para executar um loop para ler a entrada padrão e gravar na saída padrão.

zsh faz esse trabalho substituindo um comando configurável pelo usuário nesse caso "comando nulo". O comando não está visível na linha de comando, mas ainda está lá. Um processo é criado para isso e funciona da mesma maneira. NULLCMD é cat por padrão, então < from > to na verdade significa cat < from > to em zsh , a menos que NULLCMD esteja definido como algo diferente; é um comando "gato implícito".

Um "uso inútil de gato" ocorre quando cat é usado como intermediário para ler de um arquivo e alimentar os dados para outro processo, cujo descritor de arquivo pode ser conectado ao arquivo original.

Se cat for removível da situação, de forma que os comandos restantes ainda possam executar a mesma tarefa, isso é inútil. Se não for removível, então não é inútil.

# useless, removable:
$ cat archive.tar | tar tf -    #  -->  tar tf archive.tar

# not removable (in POSIX shell):
$ cat > file
abc
[Ctrl-D]

# likewise:
STRING=$(cat file)

Um cat que é substituível não é a mesma coisa. Por exemplo, em vez de cat > file , podemos usar vi file para criar o arquivo. Isso não conta como remoção de cat , enquanto usa o que resta para realizar a mesma tarefa.

Se cat for o comando somente no pipeline, então é claro que não pode ser removido; nenhum rearranjo do que sobrar fará o trabalho equivalente.

Alguns gerenciadores de scripts de shell usam cat porque acham que eles podem mover o operando de entrada para mais perto do lado esquerdo da linha de comando. No entanto, os redirecionamentos podem estar em qualquer lugar na linha de comando:

# If you're so inclined:
# move source archive operand to the left without cat:
$ < archive.tar tar xf - > listing
    
por 17.12.2015 / 03:51
1

< file1 > file2 Parece ser dependente do shell, no zsh funciona, no bash não.

editar: declaração falsa excluída

    
por 16.12.2015 / 21:04
1

Além de todas as boas respostas, você pode evitar um UUOC ao simular a cat :

awk 1 file1 > file2   # For line-oriented text, not binaries.
dd if=file1 of=file2  # Works for binary files, too.
# many more geeky ways.

Esses comandos não copiam os metadados do arquivo, como seria um cp normal.

    
por 17.12.2015 / 22:17
0

Se funcionar, não corrija.

eu usaria

cat < file1 > file2

e não se preocupe com o PC da semântica.

    
por 18.12.2015 / 20:00