Insira imediatamente o último diretório que você renomeou

4

Eu tenho um diretório localizado em /var/www/html . Renomeiei esse diretório com mv de example1 para example2 .

Como eu poderia inserir o novo dir no momento em que o namechange foi feito?

Como você conseguiria isso? Pode fazer com find , mmin , 0*60 ?

Eu pretendo renomear e entrar em uma operação em vez de duas operações diferentes.

Idealmente, eu visaria uma solução de linha única e sem personalizar nada no sistema.

    
por JohnDoea 12.06.2017 / 06:02

5 respostas

7

Você pode adicionar isso em seu arquivo .bashrc ou .bash_aliases (ou equivalente se o seu shell não for bash ):

mvcd () {
    mv -- "$1" "$2" &&
      cd -P -- "$2"
}

Em seguida, reinicie o seu shell, então você pode usar a função da seguinte forma:

mvcd foo bar

Isso pressupõe que $2 não é um diretório existente, caso contrário, mv moverá $1 para ao invés de para (veja o -T opção do GNU mv para proteger contra isso).

-- marca o final das opções. mv "$1" "$2" seria mv "$option_or_source" "$option_or_argument_to_first_option_or_destination" . mv -- "$1" "$2" garante que $1 e $2 não sejam tratados como opções, mesmo se o nome deles começar com - , portanto, sempre será tratado como mv -- "$source" "$destination" . Geralmente, você deseja usar -- sempre que um comando receber um argumento arbitrário.

-P (para a passagem de diretório físico ) é para impedir o processamento especial que o cd embutido de shells POSIX faz por padrão com .. caminho componentes para que ele trate o conteúdo de $2 o mesmo que mv . Sem isso, em cdmv foo ../bar , cd poderia fazer o cd em um diretório bar diferente daquele mv renamed foo as.

Se você definiu $CDPATH (ou estava no ambiente quando o shell foi iniciado), também seria necessário desativá-lo para essa invocação de cd :

mvcd () {
    mv -- "$1" "$2" &&
      CDPATH= cd -P -- "$2"
}

Alguns problemas extras de caso de canto permanecem: - (e em alguns shells -2 , +3 ) são tratados especialmente mesmo após -- . Se você quiser renomear foo para - , use mvcd foo ./- em vez de mvcd foo - .

    
por 12.06.2017 / 06:31
3

Em ksh93 e bash :

$ pwd
/tmp
$ mkdir test_dir
$ mv test_dir another_name
$ cd $_
$ pwd
/tmp/another_name

$_ expande para o último argumento do comando anterior.

Como uma função shell:

mvcd () {
    mv -- "$1" "$2"
    cd -P -- "$_"
}

Mas você também pode usar

mvcd () {
    mv -- "$1" "$2" &&
    cd -P -- "$2"
}

como isso iria cuidar de não tentar mudar de diretório se o mv falhou.

O traço duplo é necessário para permitir nomes que começam com um traço. O traço duplo sinalizará o fim das opções da linha de comando e impedirá que o nome seja interpretado como uma opção, nesses casos.

O -P com cd é necessário para tornar cd interpretar os caminhos da mesma maneira que mv ("fisicamente" em vez de "logicamente"). Isso evita confusão quando o novo local é especificado com um caminho que contém .. e percorre links simbólicos.

Se você mover, em vez de apenas renomear o diretório, será preciso resolver o caso em que o movimento não envolve a renomeação do diretório:

mv some_dir existing_dir

Isso moveria some_dir para existing_dir , então seria necessário

cd existing_dir/some_dir

para alterar o diretório de trabalho para o diretório movido posteriormente.

A seguinte função shell modificada cuida disso:

mvcd () {
    if [ -d "$2" ]; then
        mv -- "$1" "$2" &&
        cd -P -- "$2/$1"
    else
        mv -- "$1" "$2" &&
        cd -P -- "$2"
    fi
}

ou "menor":

mvcd () {
    if [ -d "$2" ] && mv -- "$1" "$2"; then
        cd -P -- "$2/$1"
    elif mv -- "$1" "$2"; then
        cd -P -- "$2"
    fi
}

Não há como combinar o mv e o cd em uma operação verdadeiramente atômica. O mv tem que acontecer primeiro, depois o cd , não importa como você o veja, mesmo que você o tenha escrito em C. Fazer um após o outro (enquanto verifica o status de saída de mv ) é o correto maneira de fazer isso.

    
por 12.06.2017 / 09:45
2

Quando você renomeia um arquivo (do tipo diretório ou outro), você não o modifica¹¹, então o horário da última modificação não muda. Seu tempo alterar status (como verificado por -cmin em vez de -mmin ) é atualizado (pelo menos no Linux, o POSIX não dá garantia sobre isso).

As coisas que são modificadas são os diretórios dos quais você move o arquivo (à medida que uma entrada é excluída / renomeada) e como (uma entrada é adicionada / renomeada nela). O tempo de status de alteração também foi modificado.

Então, se você quiser que uma heurística encontre o diretório renomeado mais recentemente, uma abordagem seria encontrar o arquivo com o ctime mais recente, cuja hora é diferente do mtime.

Com zsh:

ctime_is_mtime() {
  zmodload zsh/stat
  local -A stat
  zstat -H stat -- $REPLY &&
    ((stat[ctime] == stat[mtime]))
}

cd ./**/*(D/oc^+ctime_is_mtime[1])

Os qualificadores da glob explicaram:

  • D não ignora arquivos ocultos e dirs
  • / considera apenas arquivos do tipo diretório
  • oc sort by ctime
  • ^ não
  • +ctime_is_mtime chama a função para verificar ctime em relação a mtime.

Observe que a granularidade de tempo está reduzida ao segundo somente mesmo em sistemas de arquivos que suportam granularidade de subsegundo.

Outros casos em que ctime é modificado, mas não mtime incluem qualquer modificação nos metadados, exceto atime no acesso (como chmod , chown , setfacl ...) e usando touch definir um horário de modificação arbitrário é outro caso em que ctime e mtime podem ser diferentes.

¹ bem tecnicamente, para um diretório, quando movido para um diretório diferente, você altera sua .. entry (que agora aponta para o novo diretório pai) para os sistemas de arquivos que ainda armazenam "." físicos. e ".." entradas nos diretórios em vez de falsificá-los no nível do sistema operacional. No entanto, os sistemas AFAICT ainda não alteram o mtime nesse caso.

    
por 12.06.2017 / 08:26
1

Para finalizar a tentativa de responder sem personalizar nada no sistema, você pode fazer o seguinte:

TARGET="tgt_name"; mv src_name ${TARGET}; cd ${TARGET}

Obviamente, você pode escolher um nome de variável mais curto como A , mas observe que isso pode sobrescrever variáveis em sua sessão atual. Se você está preocupado com isso, considere configurar o ambiente para um subshell:

env TARGET="tgt_name" bash -c 'mv src_name ${TARGET}; cd ${TARGET}'

A essa altura, acho que cruzamos mais a linha de conveniência versus complicação, e seria muito melhor personalizar o sistema com a função mvcd da resposta de Lie Ryan.

    
por 12.06.2017 / 08:40
0

Você pode alterar o diretório antes de chamar mv . Isso deixa o shell confuso sobre o diretório de trabalho atual. Isso é inofensivo para aplicativos, desde que a origem e o destino estejam no mesmo sistema de arquivos, mas deixa a variável PWD , o pwd builtin e o prompt mostrando o local antigo, entre outros. Para atualizar pwd e amigos, em zsh e bash, você pode usar cd . ; mas em outras shells isso não faz nada e você precisa de cd 'pwd -P' ; em ambos os casos, isso não retém nenhuma informação sobre links simbólicos.

cd /some/where
mv "$PWD" /else/where
cd .                     # works in bash and zsh; use cd "'pwd'" in other shells

Você pode deixar de fora as aspas em torno de $PWD se ele não contiver nenhum caractere especial de shell. Você não pode usar . como a origem do mv porque . não pode ser movido, a movimentação requer uma entrada de diretório "true".

Esta solução tem a vantagem de não precisar digitar nenhum caminho mais de uma vez, e é robusta em relação aos dois modos de operação de mv , quer seu segundo argumento seja um diretório existente ou não.

Você pode colocar isso em uma função, embora o principal benefício dessa abordagem seja que ela envolve pouca digitação e não beneficia muito de uma função. Se você decidir usar uma função, eu recomendaria uma das abordagens abaixo.

Se você fizer as coisas ao contrário, uma solução de uma linha terá que sacrificar muitos casos. O último argumento para mv pode ser um diretório existente, em cujo caso a origem é movida para esse diretório e retém seu nome base, ou não, caso em que o nome final é o destino. Aqui está uma função que lida com ambos os casos, permanecendo simples (o que significa que ele perde muitos casos de borda).

mvcd () {
  mv "$@" && 
  if [ $# -eq 2 ] && [ ! -d "$2" ]; then
    cd "$2"
  else
    shift $(($#-2))
    cd "$2/${1##*/}"
  fi
}

Eu uso uma função maior e mais robusta que define a variável moved para a lista de arquivos de destino. Ainda pode ser enganado, mas você tem que trabalhar mais. Eu só me preocupei em escrevê-lo para o zsh, mas ele pode ser adaptado para o bash e o ksh.

function mv {
  emulate -LR zsh
  setopt extended_glob
  local i target=
  moved=("$@")
  while [[ $moved[1] == -* ]]; do
    case $moved[1] in
      -t?*) target=${moved[1]#*t};;
      --t*=*) target=${moved[1]#*=};;
      -t|--t*) target=$moved[2]; shift moved;;
      -S|--su) shift moved;;
      --) break;;
    esac
    shift moved
  done
  if [[ -z $target ]]; then
    target=$moved[-1]
    moved=($moved[1,-2])
  fi
  target=${target%%/##}
  if [[ -d $target ]]; then
    for ((i=1; i<=$#moved; i++)); do
      moved[$i]=$target/${${moved[i]%%/##}##*/}
    done
  else
    moved=($target)
  fi
  command mv "$@"
}

Depois de um comando mv , posso fazer coisas como ls -ld $moved , cd $moved , xdg-open $moved (é o que mais uso) etc. Por exemplo:

mvcd () {
  mv "$@" && cd -- $moved[-1]
}
    
por 12.06.2017 / 14:26