Why does echo "$(fc -l -1)" show the previous command, but echo "$(fc -l -1 | cat)" show the current command?
$ testfc () { > echo "$(fc -l -1)" > echo "$(fc -l -1 | cat)" > } $ echo foo foo $ testfc 1820 echo foo 1821 testfc More detail
I was testing things for a rabbit-hole question and ended up down another rabbit hole. I created this function to try different ways of accessing the previous or current command history number with the fc and history built-ins:
testfc () { printf 'fc1\t'; fc -l -1 printf 'fc1|\t'; fc -l -1 | cat printf '(fc1)\t%s\n' "$(fc -l -1)" printf '(fc1|)\t%s\n' "$(fc -l -1 | cat)" # this one is weird printf 'fc0\t'; fc -l -0 printf 'fc0|\t'; fc -l -0 | cat printf '(fc0)\t%s\n' "$(fc -l -0)" printf '(fc0|)\t%s\n' "$(fc -l -0 | cat)" printf 'hist\t'; history 1 printf 'hist|\t'; history 1 | cat printf '(hist)\t%s\n' "$(history 1)" printf '(hist|)\t%s\n' "$(history 1 | cat)" str='\!' printf '@P\t%s\n' "${str@P}" printf 'HC\t%s\n' "$HISTCMD" } Generally, fc -l -0 & history 1 show the current command, and fc -l -1 shows the previous command. Their outputs don't change when run in a $() subshell or piped through cat. Except "$(fc -l -1 | cat)"!
1831 $ echo foo foo 1832 $ testfc fc1 1831 echo foo fc1| 1831 echo foo (fc1) 1831 echo foo (fc1|) 1832 testfc # <-- WHAT? fc0 1832 testfc fc0| 1832 testfc (fc0) 1832 testfc (fc0|) 1832 testfc hist 1832 2025-05-02 15:10:59 testfc hist| 1832 2025-05-02 15:10:59 testfc (hist) 1832 2025-05-02 15:10:59 testfc (hist|) 1832 2025-05-02 15:10:59 testfc @P 1832 HC 1832 1833 $ fc -l -2 1831 echo foo 1832 testfc Context
$ echo $BASH_VERSION 5.2.37(1)-release $ type fc fc is a shell builtin $ type history history is a shell builtin $ type cat cat is /usr/bin/cat
fcin a subshell writes its own history into$HISTFILE, with a 4K buffer. That's the history that(fc)searches. Outside a subshell,fcaccesses the normal$HISTORY.| catchange its output?