Лучший способ подкачать имена файлов

$ ntpdate -q pool.ntp.org
server 86.59.113.118, stratum 2, offset 0.007942, delay 0.07298
server 147.251.48.140, stratum 2, offset -0.001173, delay 0.05101
server 212.18.3.19, stratum 2, offset -0.003886, delay 0.04689
7
01.03.2015, 21:15
5 ответов

Вот то, что я оказался:

file1=1stfile
file2=2ndfile
temp="$(mktemp -dp /mnt/sdcard)"
mv "$file1" $temp
mv "$file2" "$file1"
mv $temp/"$file1" "$file2"
2
27.01.2020, 20:18

Это более устойчиво:

TMPFILE=tmp.$$
mv -- "$file1" $TMPFILE && mv -- "$file2" "$file1" && mv -- $TMPFILE "$file2"

заключение в кавычки для предотвращения проблем с пробелами в именах файлов, оно использует tmp файл, и && делают следующую команду выполненной, только если предыдущее закончилось успешно.

1
27.01.2020, 20:18
  • 1
    Как это? file1=1stfile && file2=2ndfile && temp="$(mktemp -dp /mnt/sdcard)" && mv "$file1" $temp && mv "$file2" "$file1" && mv $temp/"$file1" "$file2".Работает. Спасибо за Ваш вход. –  Binoy Babu 28.02.2012, 03:47
  • 2
    видит, что этот stackoverflow.com/q/9475497/1068546 –  Binoy Babu 28.02.2012, 05:04
  • 3
    использовать mktemp хорош; хороший –  guido 28.02.2012, 05:10
  • 4
    находки, но выполнение команды с && в Java с runtime.exec () не работает. :( –  Binoy Babu 28.02.2012, 05:15
  • 5
    необходимо заключить yourShellInput переменную в кавычки: Представьте yourShellInput в виде строки = "\"эхо привет &&, повторяют ho \""; или если ouy имеют двойные кавычки в Вашей командной строке yourShellInput = "'эхо привет &&, повторяют ho'"; право –  guido 28.02.2012, 05:33

Нет низкоуровневого способа подкачки файлов, поэтому необходимо использовать промежуточное временное имя. Для надежности убедитесь, что временное имя не будет использоваться другой программой (поэтому используйте mktemp) и что оно находится в той же файловой системе, что и один из файлов (в противном случае файлы будут ненужно скопированы, а не просто переименованы).

swap_files () {
  tmp_name=$(TMPDIR=$(dirname -- "$1") mktemp) &&
  mv -f -- "$1" "$tmp_name" &&
  mv -f -- "$2" "$1" &&
  mv -f -- "$tmp_name" "$1"
}
swap_files file file_1

Остерегайтесь, что в случае ошибки первый файл может все еще находиться под временным именем, а второй файл может быть перемещен или еще не перемещен. Если вам нужна робастность в случае прерываний и сбоев, вариант с двумя временными именами может быть легче восстановить.

swap_files2 () {
  tmp_dir1=$(TMPDIR=$(dirname -- "$1") mktemp -d .swap_files.XXXXXXXXXXXX) &&
  tmp_dir2=$(TMPDIR=$(dirname -- "$2") mktemp -d .swap_files.XXXXXXXXXXXX) &&
  mv -f -- "$1" "$tmp_dir1/" &&
  mv -f -- "$2" "$tmp_dir2/" &&
  mv -f -- "$tmp_dir1/"* "$1" &&
  mv -f -- "$tmp_dir2/"* "$2" &&
  rmdir -- "$tmp_dir1" "$tmp_dir2"
}

Если временные каталоги .swap_files.???????????? присутствуют при перезагрузке, это означает, что обмен файлами был прерван из-за сбоя питания. Остерегайтесь, что один из файлов уже был перемещен на место, а другой нет, поэтому код здесь не учитывает все случаи, это зависит от того, какое восстановление вы хотите.

3
27.01.2020, 20:18

Системный вызовrenameat2в системах Linux с флагом RENAME_EXCHANGEдолжен делать именно это, это инструмент командной строки, который утверждает, что использует его.

9
20.08.2021, 13:28

Я опоздал на вечеринку, но если вы не возражаете против установки tcc(, доступного в репозиториях всех основных дистрибутивов Linux ), вы можете использовать renameat2, выполнив JIT-компилятор для замены имени на низком уровне. инструмент:

swapname() {
    tcc -run - "$@" <<"CODE"
    #include <unistd.h>
    #include <fcntl.h> 
    #include <stdio.h>
    #include <sys/syscall.h>
    
    // Ubuntu 18.04 doesn't define this constant
    // Obtained from '/usr/include/linux/fs.h'
    // Always test first! Might not always corispond to userland 
    // RENAME_EXCHANGE
    int local_RENAME_EXCHANGE = (1 << 1);
    
    int main(int argc, char **argv) {
        if (argc != 3) { 
            fprintf(stderr, "Error: Could not swap names. Usage: %s PATH1 PATH2\n", argv[0]);
            return 2; 
        }
        int r = syscall(
            SYS_renameat2,
            AT_FDCWD, argv[1],
            AT_FDCWD, argv[2], 
            local_RENAME_EXCHANGE
        );
        if (r < 0) {
            perror("Error: Could not swap names");
            return 1;
        }
        else return 0;
    }
CODE
} 

Это приводит к чистому и простому атомарному способу замены имен файлов:

swapname "/path/to/file-1" "/path/to/file-2"
4
20.08.2021, 13:28

Теги

Похожие вопросы