Bash - lido como um fallback para $ @

0

Eu tenho um script bash (trabalhando no OSX) que pega arquivos e diretórios como entrada e faz algo como

for inputFile in $@
do
[someStuff]
done

mas eu quero fornecer um "fallback", ou seja, se o script é iniciado sem argumentos (clicado duas vezes, por exemplo), ele pode receber entrada nesse momento, deixando o usuário soltar os arquivos diretamente no terminal (possivelmente através de read mas não obrigatório, estou aberto a soluções melhores / diferentes).

Eu estou supondo que eu deveria usar algum tipo de declaração if , mas não sei como. Eu gostaria de não ter que duplicar essencialmente o tamanho do script por dois repetindo [someStuff] para cada caso.

Obrigado.

    
por user137369 09.06.2012 / 03:08

2 respostas

2
if [ $# -eq 0 ]; then
    read -p "File: " altfile
    set "$altfile"
fi

for inputFile in "$@"
    ...etc

EDIT: se você quiser permitir que vários nomes de arquivos sejam lidos, você pode fazer isso em uma única linha com espaços separando-os:

if [ $# -eq 0 ]; then
    read -p "File(s): " -a altfiles
    set "${altfiles[@]}"
fi

ou um por linha:

if [ $# -eq 0 ]; then
    altfiles=()
    echo "Enter filenames one per line, enter Control-D after the last filename"
    while read -p "File: " altfile; do
        altfiles+=("$altfile")
    done
    set "${altfiles[@]}"
fi

Note que ambos removerão as barras invertidas dos nomes dos arquivos, o que significa que você pode arrastar arquivos do Finder e eles serão analisados corretamente, mas inserir os nomes dos arquivos com caracteres engraçados manualmente pode não funcionar como esperado. / p>     

por 09.06.2012 / 06:01
1

Supondo que seu plano de backup forneça uma lista de arquivos na entrada padrão, um por linha, e seu plano principal é fornecer uma lista de arquivos na linha de comando, um por argumento:

#!/bin/bash
declare -a files # let's use an array to avoid whitespace tokenization
let filecnt=0
if [ "$#" -gt 0 ]; then
    # we have args!
    for f in "$@"; do
        files[$filecnt]="$f"
        ((filecnt++))
    done
else
    # we have filenames on stdin!
    while read -e line; do
        files[$filecnt]="$line"
        ((filecnt++))
    done
fi

# now do whatever you need to do with the filenames
for filename in "${files[@]}"; do
    echo "$filename"
done

Como é normal no Unix, Ctrl-D em sua própria linha termina stdin e permite que o programa continue.

Mas você mencionou "drop", o que me faz pensar que o que você realmente gosta é de um recurso "arrastar e soltar". Para isso, o Ornitorrinco pode ser algo para se investigar. Acredito que ele irá agregar seu script em um aplicativo que faz um alvo arrastar e soltar para você e passa os arquivos removidos como argumentos para seu script.

Atualização : Se você quisesse ter arquivos com apenas um espaço em branco antigo entre eles, para que vários arquivos pudessem estar na mesma linha, substitua-os por:

while read -ea lfiles; do
    for f in "${lfiles[@]}"; do 
        files[$filecnt]=$f
        ((filecnt++))
    done
done

Ou se você espera apenas uma linha com todos os arquivos nela, você pode simplificar todo esse loop enquanto:

read -ea files

Entretanto, esteja ciente de que, com essa abordagem, você deve digitar uma barra invertida na frente de qualquer espaço que realmente deseje fazer parte de seu caminho de arquivo ou diretório, ou o script analisará seu pathname como vários arquivos separados! (No entanto, arrastar e soltar do Finder no Terminal fará automaticamente esse escape de barra invertida para você.)

    
por 09.06.2012 / 06:55

Tags