Вы можете сделать файл настолько большим или маленьким, насколько захотите, особенно на Linux tmpfs.
df -h /tmp
Filesystem Size Used Avail Use% Mounted on
tmpfs 12G 472K 12G 1% /tmp
Мы можем просто сделать разреженный файл.
for cmd in \
'dd bs=1024k seek=20k of=' \
'ls -slh '
do eval "$cmd/tmp/file"
echo
done </dev/null
0+0 records in
0+0 records out
0 bytes (0 B) copied, 0.000152051 s, 0.0 kB/s
0 -rw-r--r-- 1 mikeserv mikeserv 20G Dec 24 20:19 /tmp/file
Видите? Он использует 0 блоков дискового пространства, но его видимый размер составляет 20 гигабайт.
Затем вы можете просто fdisk / tmp / file
. Я только что создал на нем таблицу разделов. Вот fdisk -l
:
Disk /tmp/file: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x057d787a
Device Boot Start End Sectors Size Id Type
/tmp/file1 2048 20973567 20971520 10G 83 Linux
/tmp/file2 20973568 31459327 10485760 5G 5 Extended
/tmp/file3 31459328 41943039 10483712 5G 83 Linux
После того, как таблица была записана, она действительно использует маленький бит пространства:
ls -lsh /tmp/file
8.0K -rw-r--r-- 1 mikeserv mikeserv 20G Dec 24 20:21 /tmp/file
Однако вы не знаете.
df -h /tmp
Filesystem Size Used Avail Use% Mounted on
tmpfs 12G 480K 12G 1% /tmp
И вы можете разреженно расширить файл таким же образом:
for cmd in \
'dd bs=1024k seek=30k of=' \
'ls -slh ' 'fdisk -l '
do eval "$cmd/tmp/file"
echo
done </dev/null
0+0 records in
0+0 records out
0 bytes (0 B) copied, 9.8239e-05 s, 0.0 kB/s
8.0K -rw-r--r-- 1 mikeserv mikeserv 30G Dec 26 14:24 /tmp/file
Disk /tmp/file: 30 GiB, 32212254720 bytes, 62914560 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x057d787a
Device Boot Start End Sectors Size Id Type
/tmp/file1 2048 20973567 20971520 10G 83 Linux
/tmp/file2 20973568 31459327 10485760 5G 5 Extended
/tmp/file3 31459328 41943039 10483712 5G 83 Linux
Здесь, как указал @jordanm, ваша проблема заключается в том, что вы вызываете mv
по имени файлов для каждого из каталогов, пройденных os.walk
, но os.walk
не изменяет текущий рабочий каталог.
Таким образом, для тех файлов, которые находятся в подкаталогах, это не сработает.
Вам нужно передать полный путь к файлу в mv
, что-то вроде os.path.join(dirpath, name)
.
В идеале вы хотели бы, чтобы ходьба меняла каталоги по мере продвижения, как это делаютperl
File::Find
в finddepth()
или BSD/GNU find -execdir
, что сделает его более безопасным и позволит избежать проблем с слишком глубокие деревья каталогов, но я не думаю, что вы можете легко сделать это с помощью python
's os.walk()
.
Теперь есть несколько других проблем с вашим кодом:
Теперь конечные пробелы — это наименьшая из ваших забот в этом:
subprocess.call("mv '%s' '%s'"%(name,name.strip()),shell=True)
Это в основном уязвимость внедрения команд (, например, файл с именем'$(reboot)'
(с кавычками )).
Как правило, не вставляйте произвольный текст в строки, интерпретируемые как шелл-код (или код на любом языке, который может причинить какой-либо вред ).
С вашим кодом (вариант, использующий форму 'mv "%s" "%s"'
), может привести к той же ошибке, например, с файлами с именами randconf $x
или randconf $(test)
.
Здесь используйте:
subprocess.call(("mv", "--", name, name.strip()),shell=False)
Если вам нужно использовать оболочку, лучшим способом передачи данных в эту оболочку является использование переменных среды:
os.putenv("OLD", name)
os.putenv("NEW", name.strip())
subprocess.call('mv -- "$OLD" "$NEW"',shell=True)
Запуск оболочки также обходится дорого. Особенно в системах, где sh
на самом деле представляет собой большую полнофункциональную -оболочку, такую как bash
, ksh93
или zsh
, загрузка и инициализация которой обычно занимает значительное время.
Пока вы вызываете оболочку, вы можете выполнять поиск и переименование в коде оболочки.
mv
mv
не является командой с лучшим интерфейсом(cp
и ln
имеют те же проблемы ). Проблема в том, что mv
делает много разных вещей, но не в зависимости от того, что/как вы об этом спрашиваете, а в зависимости от контекста.
mv A B
Либо
Здесь вам просто нужен базовый rename()
системный вызов или, может быть, лучше rename()
, который не затирает уже существующий файл (, как в Linux renameat2(... RENAME_NOREPLACE)
), что также облегчит проблемы, такие как "randconf_1 "
и "randconf_1 "
переименованы в randonf_1
.
В GNU mv
вы можете сделать это с помощью:
mv -nT -- "$old" "$new"
но это не переносимо. (Также обратите внимание, что GNU mv
не использует renameat2()
в Linux, поэтому имеет (второстепенное здесь )состояние гонки)
В любом случае, в python
вам не нужно вызывать отдельную программу только для переименования файла.
os.rename(name, name.strip());
(Не думаю, что python
имеет привязку к Linux'renameat2()
)
python
's strip()
удаляет начальные и конечные пробельные символы. Здесь все строки начинаются с randconf
, так что это то же самое, что и rstrip()
. пробел включает символ пробела ASCII, но всевозможные другие вертикальные и горизонтальные символы пробела (только символы ASCII, хотя ), такие как TAB, LF, CR...
Поскольку вы ищете файлы, которые содержат пробелов в любом месте строки,вы можете не переименовывать некоторые имена файлов, которые заканчиваются пробелом (, например "randconf_\t"
, который не содержит пробела ), или вызывать mv
для имен файлов, которые не заканчиваются пробелом (, например"randconf_x y"
).
Вы можете использовать fnmatch.filter(filenames, "randconf* ")
и rstrip(" ")
, если вас интересуют только конечные пробелы
Сделайте это с помощью оболочки POSIX и синтаксиса утилиты:
find. -depth -name 'randconf*[[:space:]]' ! -type d -exec sh -c '
for file do
newfile=${file%"${file##*[![:space:]]}"}
[ -e "$newfile" ] || [ -L "$newfile" ] || mv -- "$file" "$newfile"
done' sh {} +
Или немного надежнее с утилитами GNU
find. -depth -name 'randconf*[[:space:]]' ! -type d -execdir bash -O extglob -c '
for file do
newfile=${file%*([[:space:]])}
mv -nT -- "$file" "$newfile"
done' sh {} +
(обратите внимание, что он удаляет все символы, считающиеся пробелами в текущей локали, а не только символы ASCII, как в python; измените локаль на C
, чтобы соответствовать только пробелу ASCII ).