função bash para manipular o arquivo através de symlink: problema com argumentos de linha de comando

1

Eu escrevi um pequeno código que copiava arquivos com seus nomes ou links simbólicos para um determinado diretório.

linkcp() {
cp 'echo "$(realpath $1)"' "$2"
}

aqui está a lista de arquivos:

$ ls -l
drwxr-xr-x 2 user1 users 4096 apr. 30 01:20 temp
-rw-r--r-- 1 user1 users 50 apr. 30 01:20 file1
-rw-r--r-- 1 user1 users 34 apr. 30 01:20 file2
lrwxrwxrwx 1 user1 users 26 apr. 30 01:20 lnk1 -> file1
lrwxrwxrwx 1 user1 users 26 apr. 30 01:20 lnk2 -> file2

Isso funciona se eu usar:

$ linkcp lnk1 temp
$ ls temp/
$ file1

mas não se eu usar curingas (eu preciso mover todos os arquivos começando com lnk):

$ rm temp/*
$ linkcp lnk* temp
$ ls temp/
$

Se eu fizer:

$ arg=lnk*
$ cp 'echo "$(realpath $arg)"' "temp/"
$ ls temp/
$ file1  file2

Eu não sei porque usar $1 na função causa um problema?

    
por user1850133 30.04.2014 / 01:36

2 respostas

1

Como Hauke apontou, seu problema é que você está esperando 2 argumentos, mas você dá a sua função vários argumentos. O link* é expandido pelo shell antes de ser passado para a sua função, então o que você está realmente executando é

linkcp lnk1  lnk2  temp

porque lnk* se expande para lnk1 lnk2 .

Então, o que você realmente quer é algo como:

linkcp() {
    ## Save the arguments given to the function in the args array
    args=("$@");

    ## The last element of the array is the target directory
    target=${args[((${#args[@]}-1))]}

    ## If the target  is a directory
    if [ -d "$target" ];
    then
    ## Iterate through the rest of the arguments given
    ## and copy accordingly
    for((i=0; i<$#-1; i++))
    do
        cp -v "$(realpath "${args[$i]}")" "$target"
    done
    ## If the target does not exist or is not a directory, complain
    else
    echo "$target does not exist or is not a dirtectory" 
    fi
}
    
por 30.04.2014 / 13:22
0

Tente ver o que realmente acontece:

echo linkcp lnk* temp

linkcp recebe mais de dois argumentos, mas se preocupa apenas com os dois primeiros.

Você precisa de algo assim:

linkcp() {
  local i num=$# tmparray=()
  for((i=1;i<num;i++)); do
    tmparray[i]="$(realpath "${!i}")"
  done
  if [ "$#" -eq 2 -o "$#" -gt 2 -a -d "${!num}" ]; then
    echo cp "${tmparray[@]}" "${!num}"
  else
    echo "error"
  fi
}

Após o teste, remova o echo .

Isso leva um argumento por vez, determina seu nome real e chama cp com uma matriz de argumentos em vez de um único argumento. A matriz também pode conter um único argumento. Você pode adaptar o teste se cp sempre copiar para um diretório somente (e não sobrescrever arquivos ou copiar para um novo nome de arquivo).

    
por 30.04.2014 / 01:51