Поскольку оболочка gnome -предоставляет интерфейс JS eval на DBus, который имеет доступ ко всем переменным, это возможно с помощью следующей команды:
gdbus call --session --dest org.gnome.Shell \
--object-path /org/gnome/Shell \
--method org.gnome.Shell.Eval \
"imports.ui.status.keyboard.getInputSourceManager().inputSources[0].activate()"
Что активирует 0-й макет и т.д. Тривиально назначить эти команды, скажем, малоиспользуемым 無変換 и 変換 на японской клавиатуре.
А вот как переключиться на последний использованный метод ввода (из комментариев):
gdbus call --session --dest org.gnome.Shell --object-path /org/gnome/Shell \
--method org.gnome.Shell.Eval "imports.ui.status.keyboard.getInputSourceManager()._mruSources[1].activate()"
Если у вас достаточно места для сжатия файла, что должно освободить значительный объем пространства и позволить вам выполнять другие операции, вы можете попробовать это:
gzip file && zcat file.gz | tail -n +300000001 | gzip > newFile.gz
Сначала будет gzip
исходный входной файл(file
)для создания file.gz
. Затем вы zcat
только что созданный file.gz
, передаете его через tail -n +300000001
, чтобы удалить первые 3M строк, сжимаете результат для экономии места на диске и сохраняете его как newFile.gz
. &&
гарантирует, что вы продолжите только в том случае, если gzip
операция прошла успешно (она завершится ошибкой, если у вас закончится место ).
Обратите внимание, что текстовые файлы легко сжимаются. Например, я создал тестовый файл, используя seq 400000000 > file
, который печатает числа от 1 до 400 000 000, и в результате получился файл 3,7G. Когда я сжал его с помощью приведенных выше команд, сжатый файл был всего 849 МБ, а newFile.gz
я создал только 213 МБ.
Удаление первых n строк (или байтов )можно выполнить в месте -с помощьюdd
(или, альтернативно, с помощью устройств цикла). Он не использует временный файл и не имеет ограничений по размеру; однако это опасно, поскольку нет отслеживания прогресса, и любая ошибка приводит к повреждению файла.
Пример:Создайте образец файла с 1000 строками:
$ seq 1 1000 > 1000lines.txt
$ head -n 3 1000lines.txt
1
2
3
$ tail -n 3 1000lines.txt
998
999
1000
Мы хотим удалить первые 300 строк. Скольким байтам он соответствует?
$ stat -c %s 1000lines.txt
3893 # total bytes
$ head -n 300 1000lines.txt | wc -c
1092 # first 300 lines bytes
$ echo $((3893-1092))
2801 # target filesize after removal
Файл имеет размер 3893 байта, мы хотим удалить первые 1092 байта, оставив нам новый файл размером 2801 байт.
Чтобы удалить эти байты, мы используем команду GNU dd
с conv=notrunc
, иначе файл будет удален до того, как вы сможете скопировать его содержимое:
$ dd conv=notrunc iflag=skip_bytes skip=1092 if=1000lines.txt of=1000lines.txt
5+1 records in
5+1 records out
2801 bytes (2.8 kB, 2.7 KiB) copied, 8.6078e-05 s, 32.5 MB/s
Это удаляет первые 300 строк, но теперь повторяются последние 1092 байта, потому что файл еще не усечен:
$ truncate -s 2801 1000lines.txt
Это уменьшает файл до его окончательного размера, удаляя повторяющиеся строки в конце файла.
Результат:
$ stat -c %s 1000lines.txt
2801
$ head -n 3 1000lines.txt
301
302
303
$ tail -n 3 1000lines.txt
998
999
1000
Процесс для больших файлов аналогичен. Возможно, вам потребуется установить больший размер блока для повышения производительности (параметр размера блока для dd
—bs
).
Основная проблема заключается в определении правильного смещения байта для точного номера строки. В общем, это можно сделать, только читая и считая. С помощью этого метода вы должны прочитать весь файл хотя бы один раз, даже если вы отбрасываете огромный его кусок.
В некоторых файловых системах, таких как ext4 или xfs, для этого можно использовать системный вызов fallocate()
.
Я создал инструмент, который может вам пригодиться.:hexpeek — шестнадцатеричный редактор, предназначенный для работы с огромными файлами и работающий на любой последней системе POSIX -, например (, протестированной на Debian, CentOS. и FreeBSD ).
Можно использовать heexpeek или внешний инструмент, чтобы найти 300 -миллионную новую строку. Затем, предполагая, что X является шестнадцатеричным нулем -индексированной позиции первого октета после 300 -миллионной новой строки, файл можно открыть в шестнадцатеричном формате и одной командой 0, X k удалит первые X октеты в файле.
hexpeek не требует наличия tmpfile для выполнения этой операции; хотя необязательный режим резервного копирования действительно и, вероятно, должен быть отключен с помощью -флага резервного копирования (, к сожалению, текущий алгоритм резервного копирования не допускает реорганизации, затрагивающей больше файлового пространства, чем доступно для файла резервной копии ).
Конечно, пользовательская программа на C может выполнить то же самое.
Еще один голос за пользовательскую программу, если вам действительно нужна эта задача. Подойдет C или любой достаточно мощный динамический язык, такой как Perl или Python. Я не буду приводить сюда источник, но опишу алгоритм, который предотвратит потерю данных при перемещении данных:
cat
по мере необходимости. cp
или cat
. Сksh93
:
tail -n +300000001 < file 1<>; file
Оператор 1<>;
представляет собой специфическую для ksh93 -вариацию стандартного оператора 1<>
(, который открывается в режиме чтения+записи без усечения ), который усекает файл после команда вернулась в позицию, в которой команда оставила свой стандартный вывод, если эта команда была успешной.
С другими оболочками вы всегда можете выполнить усечение -в -месте -вручную с помощью perl
, например:
{
tail -n +300000001 &&
perl -e 'truncate STDOUT, tell STDOUT'
} < file 1<> file
Чтобы получить индикатор выполнения, используйтеpv
:
{
head -n 300000000 | pv -s 300000000 -lN 'Skipping 300M lines' > /dev/null &&
cat | pv -N 'Rewriting the rest' &&
perl -e 'truncate STDOUT, tell STDOUT'
} < file 1<> file
(с использованием head | pv
и cat | pv
в качестве pv
отказывался бы работать, если бы его ввод и вывод указывали на один и тот же файл. pv -Sls 300000000
также не будет работать, поскольку pv
не оставляет указатель в файле сразу после 300000000-й строки после существования, как head
делает (и требуется POSIX для файлов с возможностью поиска ). pv | cat
вместо cat | pv
позволил бы pv
узнать, сколько ему нужно прочитать, и дать вам ETA, но в настоящее время он является подделкой, поскольку не принимает во внимание случаи, когда он не читает из . ] начало этого файла, как здесь ).
Обратите внимание, что это опасно, так как файл перезаписывается на месте.Есть вероятность, что у вас закончится место на диске, если первые 300M строк содержат дыр(не должно быть для действительного текстового файла ), а остальная часть файла занимает больше места, чем у вас есть свободное место на ФС.
Вы можете просто прочитать и записать файл на месте, а затем обрезать файл. Может быть даже есть способ сделать это с помощью инструментов cli, не уверен, но вот он в Java (untested ).
RandomAccessFile out = new RandomAccessFile("file.txt", "rw");
RandomAccessFile in = new RandomAccessFile("file.txt", "r");
String line = null;
long rows = 0;
while( (line=in.readLine()) != null ){
if( rows > 300000000 ) {
out.writeBytes(line);
out.write('\n');
}
rows++;
}
in.close();
out.setLength( out.getFilePointer() );
out.close();
Существуют различные подходы к удалению первых строк. Я рекомендую вам разбить файл на куски, изменить их (, удалить первые строки )и снова объединить куски.
В вашем случае было бы очень опасно менять файл на месте -. Если что-то пойдет не так, у вас нет запасного варианта!
Вот мое рабочее решение(bash
). Возможно, вам нужны некоторые улучшения...
function split_into_chunks {
BIG_FILE=$1
while [ $(stat -c %s $BIG_FILE) -gt 0 ]
do
CHUNK_FILE="chunk.$(ls chunk.* 2>/dev/null | wc -l)"
tail -10 $BIG_FILE > $CHUNK_FILE
test -s $CHUNK_FILE && truncate -s -$(stat -c %s $CHUNK_FILE) $BIG_FILE
done
}
function concat_chunks {
BIG_FILE=$1
test ! -s $BIG_FILE || (echo "ERROR: target file is not empty"; return)
for CHUNK_FILE in $(ls chunk.* | sort -t. -k2 -n -r)
do
cat $CHUNK_FILE >> $BIG_FILE
rm $CHUNK_FILE
done
}
Тест:
$ seq 1000 > big-file.txt
$ stat -c "%s %n" chunk.* big-file.txt 2>/dev/null | tail -12
3893 big-file.txt
$ md5sum big-file.txt; wc -l big-file.txt
53d025127ae99ab79e8502aae2d9bea6 big-file.txt
1000 big-file.txt
$ split_into_chunks big-file.txt
$ stat -c "%s %n" chunk.* big-file.txt | tail -12
40 chunk.9
31 chunk.90
30 chunk.91
30 chunk.92
30 chunk.93
30 chunk.94
30 chunk.95
30 chunk.96
30 chunk.97
30 chunk.98
21 chunk.99
0 big-file.txt
$ # here you could change the chunks
$ # the test here shows that the file will be concatenated correctly again
$ concat_chunks big-file.txt
$ stat -c "%s %n" chunk.* big-file.txt 2>/dev/null | tail -12
3893 big-file.txt
$ md5sum big-file.txt; wc -l big-file.txt
53d025127ae99ab79e8502aae2d9bea6 big-file.txt
1000 big-file.txt
Подсказка :Вам обязательно нужно убедиться, что все ваши фрагменты не слишком малы (очень долгое время обработки )и не слишком велики (недостаточно места на диске )! В моем примере используется 10 строк на фрагмент -. Я предполагаю, что это слишком мало для вашей задачи.