Вы должны использовать "$0"
и dirname "$()"
.
Команды не эквивалентны, поскольку проверка оболочки влияет только на последний компонент в пути, а readlink -f
влияет на все уровни пути.
mkdir physdir
touch physdir/file
ln -s physdir symlink
test -L symlink/file ; echo $?
1
test -L symlink ; echo $?
0
dirname symlink/file
symlink
dirname "$(readlink -f symlink/file)"
/crypto/home/hl/tmp/stackexchange/readlink/physdir
Таким образом, для относительных путей вывод сильно отличается, но даже для абсолютных путей каталоги символических ссылок внутри различаются.
Не проверено
Я бы сделал что-то вроде:
#!/bin/bash
bottom=0
while [[ $bottom -lt 150000 ]] ; do
myfirst=$((bottom + 1))
mylast=$((bottom + 100000))
bottom=$((bottom + 100000))
dir="${myfirst}_$mylast"
[[ -d "$dir" ]] || mkdir "$dir"
seq $myfirst $mylast | \
while read p ; do
q="${p}_file.txt"
[[ -f "$q" ]] && echo "$q"
done | \
xargs --no-run-if-empty echo mv -t "$dir"
done
Удалите echo
из echo mv
, если хотите сделать это по-настоящему.
script.sh
#!/bin/bash
step=100000
file_dir=$1
# Counting of files in the directory
shopt -s nullglob
file_list=("${file_dir}"/*)
file_num=${#file_list[@]}
# Every file's common part
suffix='_file.txt'
for((from = 1, to = step; from <= file_num; from += step, to += step)); do
new_dir="${from}_${to}"
mkdir "${file_dir}/${new_dir}"
if ((to > file_num)); then
to="$file_num"
fi
# Generating filenames by `seq` command and passing them to `xargs`
seq -f "${file_dir}/%.f${suffix}" "$from" "$to" | xargs mv -t "${file_dir}/${new_dir}"
done
Использование:./script.sh files
Тестирование
Я сгенерировал файлы этой командой:
printf '%s\0' files/{1..1455728}_file.txt | xargs -0 touch
затем выполните:
$ time./script.sh files
# Time is:
real 10m43,618s
user 0m9,953s
sys 0m19,671s
Довольно медленно.
Результат
$ ls -1v files
1_100000
100001_200000
200001_300000
300001_400000
400001_500000
500001_600000
600001_700000
700001_800000
800001_900000
900001_1000000
1000001_1100000
1100001_1200000
1200001_1300000
1300001_1400000
1400001_1500000
В оболочке возможна арифметика, но она всегда неудобна, поэтому я рекомендую вам поискать другой язык сценариев, который сделает большую часть работы здесь. В следующем примере используется awk
, но с таким же успехом можно использовать и perl
. Я хотел бы иметь возможность сказать, что вы также можете легко использовать python
в приведенном ниже примере, но аспекты синтаксиса python
делают не очевидным, как встроить скрипт python в строку -в конвейер. так. (Это можно сделать, но это раздражающе сложно. )Обратите внимание, что я не использую awk
для выполнения ходов,просто для выполнения расчетов, необходимых для создания необходимого каталога назначения. Если вы используете perl
или python
, они также могут выполнять операции с файловой системой.
Некоторые предположения:
Вы хотите переместить файл с его полным исходным именем. Не намного сложнее изменить сценарий, чтобы удалить числовой префикс исходного (, хотя тогда лучше, чтобы файлы не заканчивались на_file.txt
).
В именах файлов есть только одна _
и нет пробелов. Если это не так, что-то вроде следующего все еще может работать, но вам нужно быть более осторожным в сценарии awk и следующем цикле оболочки.
Таким образом, с учетом этих условий должно работать следующее.
ls |
awk -F_ '
{
n = $1 - 1 # working zero based is easier here
base = n - (n % 100000) # round down to the nearest multiple of 100,000
printf "%d_%d %s_%s\n", base + 1, base + 100000, $1, $2
}' |
while read destdir orig
do
mkdir -p $destdir
mv $orig $destdir
done
Итак, что здесь происходит?
ls |...
Здесь просто перечислены имена файлов, и, поскольку вывод идет в канал, а не в терминал, они перечислены по одному в строке. Файлы будут отсортированы по порядку ls
по умолчанию, но остальная часть скрипта не заботится об этом и будет нормально работать со случайным списком имен файлов.
... | awk -F_ '
{
n = $1 - 1 # working zero based is easier here
base = n - (n % 100000) # round down to the nearest multiple of 100,000
printf "%d_%d %s_%s\n", base + 1, base + 100000, $1, $2
} |...'
Это несложно, но если вы никогда не играли с awk
раньше, это будет сложно понять. Во-первых, цель здесь состоит в том, чтобы прочитать имена файлов по одному из ls
, а затем для каждого имени файла создать строку вывода с двумя полями :первое поле с соответствующим каталогом назначения для исходного имени файла, а второе поле, передающее исходное имя файла, чтобы его могла использовать следующая часть конвейера. Итак, более подробно
Флаг -F_
для awk
указывает ему разбивать каждую строку ввода на поля по символу _
. Предполагая, что _
встречается в этих именах файлов только один раз, awk назначит $1
числовой части имени и $2
всему тексту после _
. Затем применяется раскосный блок с настройками $1
и $2
, как только что описано.
Вычисление base
определяет, к какому блоку из 100000 файлов принадлежит этот файл. Сначала вычислите n
, вычитая 1
из начального числа имени файла. Этот ноль -лежит в основе числа, что облегчает работу с модульной арифметикой, используемой в следующей строке. Затем округлите n
в меньшую сторону до ближайшего числа, кратного 100 000. Если n
уже кратно 100 000, его не трогают. (Если вы не знакомы с оператором '%', то он N % M
вычисляет остаток при делении N
на M
. Итак, 5 % 3 == 2
, 6 % 3 == 0
и так далее.)
Наконец, printf
собирает выходную линию, необходимую для следующего этапа конвейера. Он создает строку с двумя полями, разделенными пробелом. Первый — это имя целевого каталога, сгенерированное с помощью base
для получения верхней и нижней частей имени каталога; именно здесь мы возвращаемся к схеме подсчета на основе 1 -для вывода. Второе поле представляет собой реконструированное исходное имя входного файла.
... | while read destdir orig
do
mkdir -p $destdir && mv $orig $destdir
done
Это последний этап конвейера, фактически выполняющий все действия. Он считывает каждую строку, созданную сценарием awk
, как два поля, а затем
mkdir -p
(, который ничего не делает, если каталог уже существует ), Часто хорошей идеей является использование шаблона mkdir... && mv...
в сценариях оболочки, потому что, если mkdir
не удается по какой-либо причине, попытка переименования не предпринимается.
Этот шаблон из нескольких стадий конвейера, каждая из которых постепенно преобразует данные каким-то простым, но полезным способом, является очень эффективным способом написания многих видов сценариев оболочки. Он играет на сильных сторонах оболочки в управлении процессами и конвейерами,в то же время позволяя вам выполнять более сложные вычисления, с которыми оболочка не справляется, в более подходящие языки.