Подтвердить что ты не робот

Получение заголовка для отображения всех, кроме последней строки файла: замена команд и стандартное перенаправление ввода-вывода

Я пытаюсь заставить утилиту head отображать все, кроме последней строки стандартного ввода. Фактический код, который мне нужен, - это что-то вроде строки cat myfile.txt | head -n $(($(wc -l)-1)). Но это не сработало. Я делаю это на Darwin/OS X, у которого нет хорошей семантики head -n -1, которая бы получила мне подобный вывод.

Ни один из этих вариантов не работает.

cat myfile.txt | head -n $(wc -l | sed -E -e 's/\s//g')
echo "hello" | head -n $(wc -l | sed -E -e 's/\s//g')

Я тестировал больше вариантов и, в частности, нашел, что это работает:

cat <<EOF | echo $(($(wc -l)-1))
>Hola
>Raul
>Como Esta
>Bueno?
>EOF
3

Здесь работает нечто более простое.

echo "hello world" | echo $(($(wc -w)+10))

Это понятно, что я ошибочно ошибаюсь. Но это, по крайней мере, говорит мне, что программа head не потребляет стандартный ввод, прежде чем передавать материал на подзаголовок/подменю команды, удаленная возможность, но та, которую я хотел все равно исключить.

echo "hello" | head -n $(cat && echo 1)

Что объясняет поведение head и wc и их взаимодействие через подоболочки здесь? Благодарим за помощь.

4b9b3361

Ответ 1

head - неправильный инструмент. Если вы хотите увидеть все, кроме последней строки, используйте:

sed \$d

Причина, по которой

# Sample of incorrect code:
echo "hello" | head -n $(wc -l | sed -E -e 's/\s//g')

сбой заключается в том, что wc потребляет весь вход, и для head ничего не осталось. wc наследует свой stdin из подоболочки, в которой он запущен, который считывается с вывода echo. Когда он потребляет вход, он возвращается, а затем head пытается прочитать данные... но все это исчезло. Если вы хотите прочитать ввод дважды, данные должны быть где-то сохранены.

Ответ 2

head -n -1 предоставит вам все, кроме последней строки его ввода.

Ответ 3

Использование sed:

sed '$d' filename

удалит последнюю строку файла.

$ seq 1 10 | sed '$d' 
1
2
3
4
5
6
7
8
9

Ответ 4

cat myfile.txt | echo $(($(wc -l)-1))

Это работает. Это слишком сложно: вы можете просто написать echo $(($(wc -l)-1)) <myfile.txt или echo $(($(wc -l <myfile.txt)-1)). Проблема заключается в том, как вы ее используете.

cat myfile.txt | head -n $(wc -l | sed -E -e 's/\s//g')

wc потребляет все входные данные при подсчете строк. Таким образом, к моменту запуска head нет данных, которые нужно прочитать в трубе.

Если ваш вход поступает из файла, вы можете перенаправить оба wc и head из этого файла.

head -n $(($(wc -l <myfile.txt) - 1)) <myfile.txt

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

Удобно, sed предлагает способ сопоставления последней строки. Любая печать всех строк, кроме последней, или подавление последней выходной строки, будет работать:

sed -n '$! p'
sed '$ d'

Ответ 5

В Mac OS X я нашел ответ от комментария к этому Q & A.

Предполагая, что вы используете Homebrew, запустите brew install coreutils, затем используйте команду ghead:

cat myfile.txt | ghead -n -1

Или, что эквивалентно:

ghead -n -1 myfile.txt

Наконец, см. brew info coreutils, если вы хотите использовать команды без префикса g (например, head вместо ghead).

Ответ 6

awk 'NR>1{print p}{p=$0}'

Для этого задания awk one-liner немного длиннее, чем sed.