Convertendo um comando de trabalho no arquivo de script de shell que obtém argumentos

0

Olá, meu comando de trabalho é:

grep -l "my text" file*.ext|xargs ls -lart

este comando é muito útil para mim e eu queria criar um arquivo de shell que faz isso com menos digitação, assim:

fn "my text" file*.ext

Eu vim para este arquivo de script de shell:

grep -l "$1" "$2"|xargs ls -lart

que não está funcionando, mesmo a primeira parte não está funcionando:

grep -l "$1" "$2"

que retorna nulo

    
por hmmftg 29.07.2018 / 11:15

2 respostas

1

Seu script precisará levar mais de dois argumentos.

Antes do shell executar grep no comando

grep -l "my text" file*.ext

o padrão de globbing de nome de arquivo file*.ext é expandido para todos os nomes de arquivos correspondentes. A linha de comando que é finalmente executada, portanto, será

grep -l "my text" file1.ext file2.ext file3.ext

(se esses são os arquivos que correspondem ao padrão)

Portanto, seu script pode parecer

#!/bin/sh

pattern=$1
shift

grep -l -e "$pattern" "$@" | xargs ls -lrt

Aqui, o padrão é salvo em uma variável e, em seguida, deslocado da lista de argumentos da linha de comando. Os argumentos restantes são uma lista de nomes de arquivos (se o padrão de globalização do nome de arquivo na linha de comando corresponder) e está disponível em "$@" .

Certifique-se de que você aspas duplas $@ . Isso fará com que $@ expanda para a lista de argumentos de linha de comando citados individualmente.

Eu removi a opção -a de ls , pois não é necessário ao fornecer nomes de arquivos explícitos para a lista. Também estou usando grep com -e para especificar o padrão, pois um padrão com um traço inicial ( - ) pode confundir grep .

Se não fosse pela classificação, eu teria sugerido o seguinte comando find em vez de seu pipeline (manipula corretamente nomes de arquivos com espaços e novas linhas):

find . -type f -name "$filepattern" -exec grep -q -e "$pattern" {} ';' -ls

Isso procura arquivos com nomes correspondentes ao que está em $filepattern e com conteúdo correspondente ao que está em $pattern e, em seguida, produz a saída em ls -l . A pesquisa é realizada recursivamente no diretório atual.

Como parte de um script:

#!/bin/sh

pattern=$1
filepattern=$2

find . -type f -name "$filepattern" -exec grep -q -e "$pattern" {} ';' -ls

Este script precisaria ser chamado de tal forma que o padrão globbing do nome do arquivo não seja expandido pelo shell ao chamá-lo:

$ ./script.sh 'my text' 'file*.ext'
    
por 29.07.2018 / 11:25
1

Para torná-lo um pouco mais seguro, contando com as extensões GNU:

#! /bin/sh -
pattern=${1?pattern required}; shift
: "${1?no filename specified}"
grep -l --null -e "$pattern" -- "$@" |
  xargs -r0 ls -lrtd --

Com --null / -0 , evitamos problemas com nomes de arquivos que contêm espaços em branco ou citações ou barras invertidas.

Com -e "$pattern" , evitamos problemas com padrões que começam com - .

Com -- , evitamos problemas com nomes de arquivos que começam com - .

Com -d , evitamos possíveis confusões se os arquivos do diretório de tipos coincidirem.

Com -r , evitamos listar o diretório atual se não houver nenhum arquivo correspondente.

Observe que, para um grande número de arquivos, xargs pode optar por executar mais de um ls invocação com parte da lista de arquivos, o que significa que a saída não seria listada corretamente por hora.

Observe também que - significaria stdin para grep , mas o arquivo chamado - no diretório atual para ls . O GNU grep -l produziria (standard input) (ou sua tradução no seu idioma). Se você quiser especificar o arquivo chamado - no diretório atual, use ./- em vez de - .

    
por 29.07.2018 / 13:01