Shell output of command executed via script or shell alias differs from output when same command run directly in terminal

I have tried two separate shells ( sh and tcsh ) to see if there is any change to this behaviour but there is no change.
I have checked man pages of each command and shell to see if there is something that i have missed or
misunderstood. I have also tried searching online, but so far i have been unable to locate anything that provides an explanation.

The command that I am using is meant to generate a playlist of media files, run from within the directory of said files I
wish to make a playlist of.

The command is: ls > zz && sed '$d' zz > pl.m3u && rm zz

If for example I am in a directory /usr/local/home/user/media, in which there are the following files:

File.S01E01.mkv
File.S01E02.mkv
File.S01E03.mkv
File.S01E04.mkv
File.S01E05.mkv


when i run the above command directly from the terminal it will create the file pl.m3u and contain a list of all of the
files as presented above in the "media" directory.

However if i use that same command in ~/.shrc as:

Code:
alias mpl="ls > zz && sed '$d' zz > pl.m3u && rm zz"

Or as a script mpl.sh:

Code:
#! /bin/sh
ls > zz && sed '$d' zz > pl.m3u && rm zz

Or if using tcsh

Code:
#! /bin/tcsh
ls > zz && sed '$d' zz > pl.m3u && rm zz

with the corresponding alias in ~/.tcshrc

the output from either the alias or script is as follows:

File.S01E01.mkv
File.S01E02.mkv
File.S01E03.mkv
File.S01E04.mkv
File.S01E05.mkv
zz


when using a script i have it placed in ~/.local/share/scripts and call it from that path after of course having chmod +x.
After having added the alias to .shrc for example, i will typically exit the terminal, and re-open it as i have found that source .shrc
results in the error "/bin/sh: source: not found"

I was wondering if anyone might have any ideas as to why the differing output is occurring.

[EDIT: Spelling]
 
alias mpl="ls > zz && sed '$d' zz > pl.m3u && rm zz"
type alias after and you will get it
$d is expanded to nothing and sed wont delete the last line
alias mpl='ls > zz && sed "\$d" zz > pl.m3u && rm zz will work
 
alias mpl="ls > zz && sed '$d' zz > pl.m3u && rm zz"
type alias after and you will get it
$d is expanded to nothing and sed wont delete the last line
alias mpl='ls > zz && sed "\$d" zz > pl.m3u && rm zz will work
Coool, I was aware that sed would'nt delete the last line, but i am still unclear as to why, if i run the command in terminal i get the desired output in my file, whereas if it was in the script or alias it didnt???
 
Problem 1: What are you trying to accomplish here? I think all your script/alias/... does is make a list of all files with names like File...mkv. Why do you even go through the intermediary file zz? You could just do "ls > pl.m3u", and be done.

Do you want to see all possible files in your playlist? What if your directory contains other, non-playable files? How about "ls *.mkv > pl.m3u"?

Next problem: You are using an intermediate file in shell. That is very rarely needed. For example, if you had to do some post-processing (for example use sed to change certain things on each line), you don't need to first store the output of ls:
Wrong: ls *.mkv > zz && sed s/File/Music/ zz > pl.m3u && rm zz
Right: ls *.mkv | sed s/File/Music/ > pl.m3u

Next problem: If you really need intermediate files, don't put them into the current directory, use /tmp instead. Then they don't pollute the place where you're working.

And finally, your real problem is quoting. The sed command you are using contains a $ sign. To the shell, the $ sign is special: It means expand a variable, even if the variable does not exist. In order to get the $ sign as an argument into sed, you have to protect it from the shell. That can be done by putting a backslash in front of it like \$, but the shell will remove the backslash. Or it can be done by guarding the string including the $ sign in quotes, like 'something $ other' or "something $ other". Note that different quotes (single versus double) have different rules whether $ sign inside will be expanded or not. If the string you are typing is processed by the shell twice (for example in the alias situation), one layer of protection will be stripped the first time, and then the second time the unprotected $ sign will be expanded. The art of shell programming is to understand how quoting works.
 
Problem 1: What are you trying to accomplish here? I think all your script/alias/... does is make a list of all files with names like File...mkv. Why do you even go through the intermediary file zz? You could just do "ls > pl.m3u", and be done.

Do you want to see all possible files in your playlist? What if your directory contains other, non-playable files? How about "ls *.mkv > pl.m3u"?

Next problem: You are using an intermediate file in shell. That is very rarely needed. For example, if you had to do some post-processing (for example use sed to change certain things on each line), you don't need to first store the output of ls:
Wrong: ls *.mkv > zz && sed s/File/Music/ zz > pl.m3u && rm zz
Right: ls *.mkv | sed s/File/Music/ > pl.m3u

Next problem: If you really need intermediate files, don't put them into the current directory, use /tmp instead. Then they don't pollute the place where you're working.

And finally, your real problem is quoting. The sed command you are using contains a $ sign. To the shell, the $ sign is special: It means expand a variable, even if the variable does not exist. In order to get the $ sign as an argument into sed, you have to protect it from the shell. That can be done by putting a backslash in front of it like \$, but the shell will remove the backslash. Or it can be done by guarding the string including the $ sign in quotes, like 'something $ other' or "something $ other". Note that different quotes (single versus double) have different rules whether $ sign inside will be expanded or not. If the string you are typing is processed by the shell twice (for example in the alias situation), one layer of protection will be stripped the first time, and then the second time the unprotected $ sign will be expanded. The are of shell programming is to understand how quoting works.
Your "finally" is really what I was after, as i was confused by the discrepancy of running the command directly rather than via a script. Cheers. I am not at all au fey with programming in general, let alone the mystical arts of sed, awk, &etc, but I am slowly learning as I bumble through. As regards the specific use of the command for generating a playlist the "right" answer as provided would not be ideal, as unless all the media files I had in the media folder were .mkv ( which is possible, though probably not entirely likely) I wouldn't be able to generate a full list if I were after say, a playlist of episodes of whatever show i totally legally obtained, but i take your point :)
 
Back
Top