Formatar saída de xargs

10

Gostaria de alterar o formato da saída que xargs exibe

cat k.txt 
1 
2 
3 

E

cat k.txt | xargs 
1 2 3

No entanto, eu gostaria de ter 1, 2, 3ou 1|2|3. Alguma sugestão?

Avinash
fonte
Isso pode ser conseguido com algo (não exatamente isso) como xargs cat -n, mas é mais fácil se você apenas aparar os caracteres de nova linha, isso pode ser conseguido com echo $(cat), grepou awk(rastreie o caminho para fazê-lo). xargsnão se encaixa bem no seu objetivo atual.
41754

Respostas:

18

Abaixo estão uma dúzia de exemplos de como você pode obter um arquivo como este:

$ cat k.txt
1
2
3

e converta-o para este formato:

1,2,3

Você pode usar este comando para criar o arquivo acima, se desejar jogar junto:

$ cat <<EOF > k.txt
1
2
3
EOF

Os exemplos abaixo são divididos em 2 grupos. Os que "trabalham" e os que "quase" funcionam. Deixo isso porque muitas vezes é tão valioso ver por que algo não funciona, como é ver por que algo funciona.

A maioria das linguagens de script que eu conheço são representadas. Alguns são representados várias vezes, pois, como acontece com o famoso acrônimo geralmente mencionado em Perl, TIMTOWTDI .

NOTA: Você pode trocar a vírgula ( ,) nos exemplos abaixo e substituí-la pelos caracteres que desejar, ou seja |.

Exemplos que "funcionam"

Esses trechos de código produzirão a saída desejada.

O pastecomando:

$ paste -s -d ',' k.txt 
1,2,3

O sedcomando:

$ sed ':a;N;$!ba;s/\n/,/g' k.txt
1,2,3

$ sed ':a;{N;s/\n/,/};ba' k.txt 
1,2,3

O perlcomando:

$ perl -00 -p -e 's/\n(?!$)/,/g' k.txt
1,2,3

$ perl -00 -p -e 'chomp;tr/\n/,/' k.txt
1,2,3

O awkcomando:

$ awk '{printf"%s%s",c,$0;c=","}' k.txt
1,2,3

$ awk '{printf "%s,",$0}' k.txt | awk '{sub(/\,$/,"");print}'
1,2,3

$ awk -vORS=, 1 k.txt | awk '{sub(/\,$/,"");print}'
1,2,3

$ awk 'BEGIN {RS="dn"}{gsub("\n",",");print $0}' k.txt | awk '{sub(/\,$/,"");print}'
1,2,3

O pythoncomando:

$ python -c "import sys; print sys.stdin.read().replace('\n', ',')[0:-1]" <k.txt
1,2,3

$ python -c "import sys; print sys.stdin.read().replace('\n', ',').rstrip(',')" <k.txt
1,2,3

O Bash mapfileembutido:

$ mapfile -t a < k.txt; (IFS=','; echo "${a[*]}")
1,2,3

O rubycomando:

$ ruby -00 -pe 'gsub /\n/,",";chop' < k.txt
1,2,3

$ ruby -00 -pe '$_.chomp!"\n";$_.tr!"\n",","' k.txt
1,2,3

O phpcomando:

$ php -r 'echo strtr(chop(file_get_contents($argv[1])),"\n",",");' k.txt
1,2,3

Ressalvas

A maioria dos exemplos acima funcionará bem. Alguns têm problemas ocultos, como o exemplo do PHP acima. A função chop()é na verdade um alias para rtrim(), portanto, os espaços à direita da última linha também serão removidos.

O mesmo acontece com o primeiro exemplo de Ruby e o primeiro exemplo de Python. A questão é como todos eles estão usando um tipo de operação que essencialmente "corta", cegamente, um personagem final. Isso é bom no exemplo que o OP forneceu, mas é preciso ter cuidado ao usar esses tipos de liners para garantir que estejam em conformidade com os dados que estão processando.

Exemplo

Diga o nosso arquivo de amostra, k.txtassim:

$ echo -en "1\n2\n3" > k.txt

Parece semelhante, mas tem uma pequena diferença. Não possui uma nova linha à direita ( \n) como o arquivo original. Agora, quando executamos o primeiro exemplo de Python, obtemos o seguinte:

$ python -c "import sys; print sys.stdin.read().replace('\n', ',')[0:-1]" <k.txt
1,2,

Exemplos que "quase" funcionam

Estes são os exemplos "sempre uma dama de honra, nunca uma noiva" . A maioria deles provavelmente poderia ser adaptada, mas ao trabalhar com uma solução potencial para um problema, quando parecer "forçado", provavelmente é a ferramenta errada para o trabalho!

O perlcomando:

$ perl -p -e 's/\n/,/' k.txt
1,2,3,

O trcomando:

$ tr '\n' ','  < k.txt 
1,2,3,

Os comandos cat+ echo:

$ echo $(cat k.txt)
1 2 3

O rubycomando:

$ ruby -pe '$_["\n"]=","' k.txt
1,2,3,

Bash's while+ readbuilt-ins:

$ while read line; do echo -n "$line,"; done < k.txt
1,2,3,
slm
fonte
1
Em relação awkEu prefiro uma alternativa mais curta:awk -vORS=, 1 k.txt
manatwork
Não tenho certeza se o CentOS possui bash:mapfile -t a < k.txt; (IFS=','; echo "${a[*]}")
manatwork
não tenho certeza sobre a nova linha à direita. De acordo com o meu teste, você perle o primeiro awktambém os têm.
manatwork
Eu colocaria pasteaquele no topo. Isso é exatamente o que paste -sé feito aqui. É um comando padrão e seria o mais eficiente. Todos os outros são um exagero e / ou não são portáteis ou têm limitações.
Stéphane Chazelas
mapfileé relativamente novo, adicionado em bash4.0.
manatwork
4

O @slm já deu uma boa resposta, mas como sua pergunta "formate a saída do xargs"

xargs -I{} echo -n "{}|" < test.txt
  • -I é a opção "substituir cadeias".
  • {} é um espaço reservado para o texto de saída.
  • Isso é semelhante ao uso de um par de chaves em "localizar".

Se você quiser se livrar da trilha, |use-a sedpara limpar:

$ xargs -I{} echo -n "{}|" < k.txt  | sed -e 's/|$//'
1|2|3
Rahul Patil
fonte
Isso prende um tubo extra depois do 3. "1 | 2 | 3 |". Eu tenho o mesmo problema com um loop while e uma solução awk.
slm
sim, se houver nova linha .. tr, sede outro também ..
Rahul Patil
2

Este é um tópico antigo, eu sei. O OP perguntou com um código simples como este. Para mantê-lo próximo ao original, tenho uma solução simples.

cat k.txt | xargs
1 2 3

use sed

cat k.txt | xargs | sed 's/ /,/g'
1,2,3

ou

cat k.txt | xargs | sed 's/ /|/g'
1|2|3

sed pode parecer um pouco estranho, mas dividido, faz muito sentido.

é substituto. g 'é global: sem isso, ele fará a primeira substituição em cada nova linha. Como você usa 'xargs', ele os exibe como uma linha. Então você receberá "1,2 3".

O delimitador é usado para separação. Eu usei o caractere /. Um truque interessante: você pode substituir o delimitador por quase qualquer outro caractere, desde que mantenha o mesmo formato entre aspas. Então isso funcionaria também ....

cat k.txt | xargs | sed 's# #,#g'

ou

cat k.txt | xargs | sed 'sT T,Tg'

Obviamente, usar certos caracteres como delimitador pode ficar confuso, portanto, seja esperto.

Michael Bruce
fonte
0
xargs <k.txt | tr \  \|

Você não precisa cat- basta passar a entrada do arquivo e - se não houver outro comando - xargsdistribuirá seu formato padrão - que é do tipo com /bin/echo's (sem interpretações de barra invertida c-escape) .

xargsretirará o espaço em branco da cabeça / cauda do arquivo de entrada e comprimirá outras seqüências de espaço em branco em um único espaço. Isso significa que, ao passar o arquivo de trpara xargs:

tr \\n \| <k.txt | xargs

... imprime ...

1|2|3|

... indo para o outro lado e operando apenas nos argumentos que xargsdelimita o espaço ...

1|2|3\n

... porque xargsimprime a nova linha final à direita (como é necessário para um arquivo de texto) , mas não é trespecificada dessa maneira.

Observe, no entanto, que esta (ou qualquer outra solução oferecida aqui) não conta com xargscitações na entrada. xargsdistribuirá literalmente caracteres de espaço em branco não-nova linha entre aspas, barra invertida / barra invertida na entrada, que podem ser citados como:

xargs <<\IN
1    2'      3'\'      \'4
IN

1 2      3' '4
mikeserv
fonte