Altere as strings em vários arquivos para o nome do subdiretório atual

2

Eu tenho vários diretórios, cada um contendo um arquivo contendo esta linha:

../a_a_q1.out ../a_a_q2.out ../a_a_q3.out

Eu gostaria de percorrer todos os subdiretórios e alterar a parte a_a para o nome do subdiretório atual. Por exemplo, se um subdiretório for chamado de awesome_directory , eu gostaria que essa linha fosse lida:

../awesome_directory_q1.out ../awesome_directory_q2.out ../awesome_directory_q3.out

Como eu conseguiria isso?

Gostaria apenas de usar o nome do subdiretório. Por exemplo, eu só precisaria da parte ( awesome_directory ) em vez da transação completa ( //something/server/user/other_stuff/more/awesome_directory )

    
por Melanie Shebel 22.07.2015 / 05:48

5 respostas

1

Em duas etapas no bash, aqui está uma maneira -

epwd=$(basename 'pwd')
sed -i "s/a_a/$epwd/g" <filename>

A variável $epwd contém um nome de diretório com escape, que pode ser usado para sed. E o comando sed substitui todas as ocorrências de a_a pelo diretório de trabalho

EDITED: A primeira linha da resposta original foi editada para ter apenas o nome do diretório atual e não o caminho completo. Se você quiser o caminho completo use

epwd=$(pwd|sed 's/\//\\//g')
    
por 22.07.2015 / 05:56
1

Eu inventei isso até agora.

var=("${PWD##*/}")

sed -i "s/a_a/$var/g" filename
    
por 22.07.2015 / 07:26
1
set '%s_q1.out %s_q2.out %s_q3.out\n'
:|for d in several directories
do      cd  -P -- "$d" || ! break
        set "$1" "../${PWD##*/}"
        {   sed -ne'\|\( \.\./a_a_q[123]\.out\)\{3\}|q;s/.//p'
            printf "$@" "$2" "$2";  cut -c2-
        } <<-IN >./infile
        $(paste -d\  - ./infile)
        IN
done

Isso deve funcionar com um POSIX sed e um bash , zsh , ksh , mksh shell e muitos outros. Com um dash ou yash shell, o documento here provavelmente não terá um arquivo regular e, portanto, não é possível confiar na função lseek() necessária para suportar o compartilhamento. Nesses casos, você deve mudar para uma das shells acima mencionadas.

Se você usar um GNU sed , você vai querer usar sed -une em vez de apenas sed -ne .

Aqui está um resumo:

  1. Primeiro, nós usaremos set um argumento como a string de formato printf repetidamente e definiremos ambos $PWD e $OLDPWD para .

  2. Em seguida, iniciamos a iteração de itens em several directories . Sejam eles diretórios ou links simbólicos reais, obtemos o nome de caminho canônico e -P em $PWD e set do último componente de caminho para $2 .

  3. A próxima coisa que acontece ocorre na parte inferior do redirecionamento heredoc. paste lê todo o ./infile para algum arquivo temporário seguro que o shell assegurou para nós enquanto prefixava um único espaço em cada linha. O shell então define esse arquivo temporário para stdin e ./infile é novamente designado - mas desta vez como stdout.

  4. sed faz muito pouca edição. Até encontrar sua linha de correspondência, ele remove o primeiro caractere de cada linha e p solicita os resultados. Uma vez que ele encontra sua linha, a entrada q uits é totalmente - nada é impresso.

  5. Mas printf imprime ../${PWD##*/}_q[123].out seguido por uma nova linha para stdout e depois cut escolhe stdin em que sed deixou (logo após a sua linha de correspondência) e lê o resto enquanto tira o primeiro byte de cada linha de entrada.

E assim todo o ./infile editado acaba de volta de onde veio.

Oh, eu testei isso.

Substitui o bit several directories pelo nome de caminho /tmp e fiz ...

{   seq 7
    echo '../a_a_q1.out ../a_a_q2.out ../a_a_q3.out'
    seq 9 14
    printf %s\n '' '' ''
}  >/tmp/infile

... que escreveu um /tmp/infile que parecia:

1
2
3
4
5
6
7
../a_a_q1.out ../a_a_q2.out ../a_a_q3.out
9
10
11
12
13
14



Depois de executar o snippet de código acima em /tmp , embora ...

cat /tmp/infile
1
2
3
4
5
6
7
../tmp_q1.out ../tmp_q2.out ../tmp_q3.out
9
10
11
12
13
14



    
por 22.07.2015 / 07:00
1

com zsh :

autoload zmv # best in ~/.zshrc
cd /something/server/user/other_stuff/more &&
  zmv -n '(*)/a_a(_*)' '$1/$1$2'

Remova -n (dry-run) se estiver feliz.

Ou de /something/server/user procurando recursivamente por a_a_* arquivos:

zmv -n '(**/)(*)/a_a(_*)' '$1$2/$2$3'

(observe que ele não procura em diretórios ocultos, adicione um (#qD) ao final do padrão para que eles sejam incluídos).

    
por 22.07.2015 / 11:04
1

Se a parte a_a for constante e você estiver executando o Linux, você poderá usar o utilitário rename . No Debian e nos derivados, altere rename para rename.ul , pois o comando rename é um utilitário diferente que também pode fazer este trabalho, mas tem uma sintaxe diferente.

Iterar os diretórios com um loop:

for d in */; do … done

Chame rename para renomear os arquivos em cada diretório.

for d in */; do
  rename /a_a "/${d%/}" "$d"a_a*
done
    
por 24.07.2015 / 02:48

Tags