Adicione argumentos interativamente linha por linha no bash

2

Às vezes acontece que eu tenho uma lista de arquivos ou strings na área de transferência e quero colá-la como uma lista de argumentos em um shell bash:

Exemplo de lista de arquivos (apenas um exemplo):

createsnapshot.sh
directorylisting.sh
fetchfile.sh

O que eu quero:

md5sum createsnapshot.sh directorylisting.sh fetchfile.sh

Atualmente, insiro a seguinte linha de comando hacky (os nomes dos arquivos são colados na área de transferência; a lista pode conter dezenas de linhas):

md5sum $(echo $(echo "
createsnapshot.sh
directorylisting.sh
fetchfile.sh
"))

Isso tem várias desvantagens:

  • é complexo
  • não parece bem
  • não suporta linhas que contenham espaços

Quais outras opções eu tenho? md5sum " não funciona porque neste caso eu recebo apenas um argumento com uma string de várias linhas. Similar com aqui-documentos.

Nem sempre é md5sum . Também pode ser tar ou git add ou du -hsc . Eu não peço apenas uma maneira de obter as somas de verificação md5 desses arquivos. Tais situações ocorrem cerca de 2-5 vezes por dia.

    
por Daniel Alder 26.11.2015 / 12:31

4 respostas

4

Se os comandos não usarem stdin , use xargs , que lê entrada e traduz para argumentos (observe que estou usando o comando echo para mostrar como xargs cria o comando):

$ xargs echo md5sum
# paste text
createsnapshot.sh
directorylisting.sh
fetchfile.sh
# press Ctrl-D to signify end of input
md5sum createsnapshot.sh directorylisting.sh fetchfile.sh

Usando xargs com -d '\n' , para que cada linha seja considerada um argumento completo, apesar dos espaços:

$ xargs -d'\n' md5sum
# paste
a file with spaces
afilewithoutspaces
foo " " bar
# Ctrl D
md5sum: a file with spaces: No such file or directory
md5sum: afilewithoutspaces: No such file or directory
md5sum: foo " " bar: No such file or directory

Como você pode ver, md5sum imprime erros para cada nome de arquivo, independentemente do outro espaço em branco nos nomes de arquivo.

Se você estiver disposto a usar xclip , então você pode canalizar ou de outra forma alimentá-lo para xargs:

xargs -a <(xclip -o) -d '\n' md5sum
xclip -o | xargs -d '\n' md5sum

Isso deve funcionar de forma confiável com nomes de arquivos com espaços.

    
por 26.11.2015 / 12:38
5

Se você não citar uma variável ou uma variável virtual como uma invocação de backtick como $(xclip -selection c -o) (produz o conteúdo de sua área de transferência X), o shell irá dividir o conteúdo em $IFS , cujo padrão é \t \n e , e expandirá globs presentes no conteúdo. Neste caso (certifique-se de inspecionar o conteúdo da sua área de transferência primeiro), é o que você quer:

md5sum 'xclip -selection c -o'

Nota:

É muito útil ter um wrapper com nome curto em torno dos comandos xclip que você precisa.

eu uso

#!/bin/sh
#filename: cb
if [ -n "$DISPLAY" ]; then
    [ -t 0 ] && exec /usr/bin/xclip -selection c -o 2>/dev/null
    /usr/bin/xclip -selection c
else
    [ -t 0 ] && exec cat "/dev/shm/$TTY_DASHED"
    cat > /dev/shm/"$TTY_DASHED"
fi

que me permite digitar cb para acessar a área de transferência e something | cb para gravar nela.

( Eu uso um arquivo na memória com o nome do meu terminal como minha área de transferência se eu estiver fora do X (= se DISPLAY não estiver definido). A variável TTY_DASHED env é definida no meu .profile como com export TTY_DASHED=$(tty |tr / - | tail -c+2) )

    
por 26.11.2015 / 13:31
3

Você pode definir uma variável contendo seus nomes de arquivos. Em seguida, use a variável em seus comandos.

$ #VAR='<paste filenames>':
$ VAR='createsnapshot.sh
>  directorylisting.sh
> fetchfile.sh'

$ touch $VAR
$ ls -l $VAR
-rw-r--r-- 1 testuser testuser 0 nov 26 12:47 createsnapshot.sh
-rw-r--r-- 1 testuser testuser 0 nov 26 12:47 directorylisting.sh
-rw-r--r-- 1 testuser testuser 0 nov 26 12:47 fetchfile.sh

$ md5sum $VAR
d41d8cd98f00b204e9800998ecf8427e  createsnapshot.sh
d41d8cd98f00b204e9800998ecf8427e  directorylisting.sh
d41d8cd98f00b204e9800998ecf8427e  fetchfile.sh

$ tar cf archive.tar $VAR
$ tar tf archive.tar
createsnapshot.sh
directorylisting.sh
fetchfile.sh

Nota: $VAR precisa ser chamado sem aspas por causa dos finais de linha. Você pode considerar usar VAR=$(echo "$VAR"|tr '\n' ' ') to be able to use quoted $ VAR '

Outra abordagem (baseada no acima) é escrever uma função no seu ~/.bashrc contendo:

fVAR () 
{ 
    VAR="$@";
    VAR=$(echo "$VAR"|tr '\n' ' ')
}

Chame a função fVAR com o conteúdo da área de transferência e os valores estão disponíveis em $VAR :

$ fVAR '<paste filenames>'
$ md5sum "$VAR"
    
por 26.11.2015 / 12:49
0
set --
while IFS= read -r in
do    set -- "$@" "$in"
done

... depois pressione as teclas shift-insert , depois ctrl + D uma vez (ou duas vezes) , e cada linha do seu colar depois pode ser literalmente (sans NULs) em $1 e $2 e $3 e assim por diante, e toda a matriz de entrada pode ser endereçada como uma única string concatenada no primeiro caractere de $IFS em "$*" ou então como uma lista de sequências separadas em "$@" , o que significa que você pode fazer:

md5sum -- "$@"

... já que aparentemente você está procurando uma útil abreviação interativa:

alias rdcb='
    [ -t 0 ] && set -- &&
    while IFS= read -r in
    do    set -- "$@" "$in"
    done'

... definirá um alias que você pode executar em um shell interativo para definir os parâmetros do shell para um array delimitado por nova linha a partir da entrada padrão.

então ...

{   ls -1 | xsel -bi                 #pipes ls output into my clipboard
    rdcb                             #terminal hangs, shift+insert && crtl+d
    xsel -bo                         #writes my clipboard to stdout
    printf %s\n '' --- '' "$@"      #writes \n-delimited shell arg array
    printf %s\n '' --- '' "$3" "$5" #writes only args "$3" and "$5"
}
1
edit.sh
paccache
sh
systemd-private-75115542eb544b09bc245e8ca7765854-systemd-timesyncd.service-CKruFk
sztally
yaourt-tmp-mikeserv

---

1
edit.sh
paccache
sh
systemd-private-75115542eb544b09bc245e8ca7765854-systemd-timesyncd.service-CKruFk
sztally
yaourt-tmp-mikeserv

---

paccache
systemd-private-75115542eb544b09bc245e8ca7765854-systemd-timesyncd.service-CKruFk

Aqui está uma versão melhor:

alias rdcb='
    if    [ -t 0 ]
    then  set -f -- "$IFS" "${IFS+IFS=\;} set +f -$-
          stty $(stty -g; stty raw -echo min 1 time 2)"
          IFS=$(printf \r)
          set -- "$@" $(dd bs=4k count=1 2>/dev/null)
          eval "unset IFS;$2;shift 2"
    fi '

Ele elimina o eco terminal e o processamento de caracteres especiais do terminal e não requer um CTRL + D para sinalizar o final da entrada. Todo o material que ele faz é temporário, e é cuidadoso em restaurar todas as configurações que ele afeta para o estado em que ele as encontrou quando passou, exceto pelos argumentos do shell, que são permanentemente alterados, por design, é claro.

Então, com isso, você acabou de fazer rdcb , depois colar e pronto. Não haverá saída para a tela quando você colar - o terminal apenas irá travar, e então você inserirá pelo menos um único byte dentro de um determinado segundo e o prompt reaparecerá. Depois disso, você pode trabalhar com os argumentos como antes.

    
por 26.11.2015 / 14:47